[Rcpp-commits] r2507 - pkg/Rcpp/inst/doc/Rcpp-modules
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Tue Nov 23 18:21:13 CET 2010
Author: romain
Date: 2010-11-23 18:21:13 +0100 (Tue, 23 Nov 2010)
New Revision: 2507
Modified:
pkg/Rcpp/inst/doc/Rcpp-modules/Rcpp-modules.Rnw
Log:
some more
Modified: pkg/Rcpp/inst/doc/Rcpp-modules/Rcpp-modules.Rnw
===================================================================
--- pkg/Rcpp/inst/doc/Rcpp-modules/Rcpp-modules.Rnw 2010-11-23 14:53:01 UTC (rev 2506)
+++ pkg/Rcpp/inst/doc/Rcpp-modules/Rcpp-modules.Rnw 2010-11-23 17:21:13 UTC (rev 2507)
@@ -19,6 +19,8 @@
\newcommand{\pkg}[1]{{\fontseries{b}\selectfont #1}}
<<echo=FALSE,print=FALSE>>=
+require( inline )
+require( Rcpp )
prettyVersion <- packageDescription("Rcpp")$Version
prettyDate <- format(Sys.Date(), "%B %e, %Y")
@
@@ -181,7 +183,55 @@
As it is generally a bad idea to expose external pointers as is,
they usually get wrapped as a slot of an S4 class.
-<<eval=FALSE>>=
+<<echo=FALSE,results=hide>>=
+f1 <- cxxfunction( , "", includes = '
+using namespace Rcpp ;
+
+class Uniform {
+public:
+ Uniform(double min_, double max_) : min(min_), max(max_){}
+
+ NumericVector draw(int n){
+ RNGScope scope ;
+ return runif( n, min, max ) ;
+ }
+
+private:
+ double min, max ;
+};
+
+/** create an external pointer to a Uniform object */
+RcppExport SEXP Uniform__new(SEXP min_, SEXP max_){
+ // convert inputs to appropriate C++ types
+ double min = as<double>(min_), max = as<double>(max_) ;
+
+ // create a pointer to an Uniform object and wrap it
+ // as an external pointer
+ Rcpp::XPtr<Uniform> ptr( new Uniform( min, max ), true ) ;
+
+ // return the external pointer to the R side
+ return ptr ;
+}
+
+/** invoke the draw method */
+RcppExport SEXP Uniform__draw( SEXP xp, SEXP n_ ) {
+ // grab the object as a XPtr (smart pointer) to Uniform
+ Rcpp::XPtr<Uniform> ptr(xp) ;
+
+ // convert the parameter to int
+ int n = as<int>(n_) ;
+
+ // invoke the function
+ NumericVector res = ptr->draw( n ) ;
+
+ // return the result to R
+ return res ;
+}
+', plugin = "Rcpp" )
+getDynLib( f1 )
+@
+
+<<>>=
setClass( "Uniform", representation( pointer = "externalptr" ) )
# helper
@@ -321,53 +371,348 @@
template.
\item The output type must be either \texttt{void} or any type that
can be managed by the \texttt{Rcpp::wrap} template.
-\item The function name itself has to be unique, in other words no two functions with
- the same name but different signatures itself are allowed (whereas this is
- possible in \proglang{C++} itself).
+\item The function name itself has to be unique in the module,
+ in other words no two functions with
+ the same name but different signatures are allowed. C++ allows overloading
+ functions. This might be added in future versions of modules.
\end{itemize}
+In addition to the name of the function and the function pointer, it is possible
+to pass a short description of the function as the third parameter of \texttt{function}.
+
+<<lang=cpp>>=
+using namespace Rcpp ;
+
+double norm( double x, double y ){
+ return sqrt( x*x + y*y ) ;
+}
+
+RCPP_MODULE(mod){
+ function( "norm", &norm, "Documentation for norm" ) ;
+}
+@
+
+The description is used when displaying the function to the R prompt:
+
+<<echo=FALSE>>=
+fx <- cxxfunction( , "", includes = '
+
+using namespace Rcpp ;
+
+double norm( double x, double y ){
+ return sqrt( x*x + y*y ) ;
+}
+
+RCPP_MODULE(mod){
+ function( "norm", &norm, "Documentation for norm" ) ;
+}
+', plugin = "Rcpp" )
+mod <- Module( "mod", getDynLib( fx ) )
+@
+<<>>=
+show( mod$norm )
+@
+
\subsection{Exposing \proglang{C++} classes}
-Rcpp modules also provide a mechanism for exposing \proglang{C++} classes. The mechanism
-internally uses external pointers, but the user should consider this as
-hidden implementation details as this is properly encapsulated.
+Rcpp modules also provide a mechanism for exposing \proglang{C++} classes, based
+on the reference classes introduced in R 2.12.0.
+\subsubsection{Initial example}
+
A class is exposed using the \texttt{class\_} class. The \texttt{World}
class may be exposed to \proglang{R} :
<<lang=cpp>>=
-class World {
+using namespace Rcpp ;
+class Uniform {
public:
- World() : msg("hello"){}
- void set(std::string msg) { this->msg = msg; }
- std::string greet() { return msg; }
+ Uniform(double min_, double max_) : min(min_), max(max_){}
+
+ NumericVector draw(int n) const {
+ RNGScope scope ;
+ return runif( n, min, max ) ;
+ }
+
+ double min, max ;
+};
-private:
- std::string msg;
+double width( Uniform* w){
+ return w->max - w->min ;
+}
+
+RCPP_MODULE(unif_module){
+
+ class_<Uniform>( "Uniform" )
+
+ .constructor<double,double>()
+
+ .field( "min", &Uniform::min )
+ .field( "max", &Uniform::max )
+
+ .method( "draw", &World::draw )
+ .method( "width", &width )
+ ;
+
+}
+@
+
+<<results=hide,echo=FALSE>>=
+fx_unif <- cxxfunction( , "", includes = '
+using namespace Rcpp ;
+class Uniform {
+public:
+ Uniform(double min_, double max_) : min(min_), max(max_){}
+
+ NumericVector draw(int n) const {
+ RNGScope scope ;
+ return runif( n, min, max ) ;
+ }
+
+ double min, max ;
};
-void clearWorld( World* w){
- w->set( "" ) ;
+double width( Uniform* w){
+ return w->max - w->min ;
}
-RCPP_MODULE(yada){
- using namespace Rcpp ;
+RCPP_MODULE(unif_module){
- class_<World>( "World" )
- .method( "greet", &World::greet )
- .method( "set", &World::set )
- .method( "clear", &clearWorld )
+ class_<Uniform>( "Uniform" )
+
+ .constructor<double,double>()
+
+ .field( "min", &Uniform::min )
+ .field( "max", &Uniform::max )
+
+ .method( "draw", &Uniform::draw )
+ .method( "width", &width )
;
}
+', plugin = "Rcpp" )
+unif_module <- Module( "unif_module", getDynLib(fx_unif ) )
@
+<<>>=
+Uniform <- unif_module$Uniform
+u <- new( Uniform, 0, 10 )
+u$draw( 10L )
+u$width()
+u$max <- 1
+u$width()
+u$draw( 10 )
+@
-\texttt{class\_} is templated by the \proglang{C++} class or struct that is to be exposed
-to \proglang{R}. The parameter of the \texttt{class\_<World>} constructor is the name we will
+\texttt{class\_} is templated by the \proglang{C++} class or struct
+that is to be exposed to \proglang{R}.
+The parameter of the \texttt{class\_<Uniform>} constructor is the name we will
use on the \proglang{R} side. It usually makes sense to use the same name as the class
name, but this is not forced, which might be useful when exposing a class
generated from a template.
+Then constructors, fields and methods are exposed.
+
+\subsubsection{Exposing constructors}
+
+Public constructors that take from 0 and 6 parameters can be exposed
+to the R level using the \texttt{.constuctor} template method of \texttt{.class\_}.
+
+Optionally, \texttt{.constructor} can take a description as the first argument.
+
+<<lang=cpp>>=
+ .constructor<double,double>("sets the min and max of the distribution")
+@
+
+Also, the second argument can be a function pointer (called validator)
+matching the following type :
+
+<<lang=cpp>>=
+typedef bool (*ValidConstructor)(SEXP*,int) ;
+@
+
+The validator can be used to implement dispatch to the appropriate constructor,
+when multiple constructors taking the same number of arguments are exposed.
+
+TODO: include example here
+
+\subsubsection{Exposing fields and properties}
+
+\texttt{class\_} has three ways to expose fields and properties, as
+illustrated in the example below :
+
+<<lang=cpp>>=
+using namespace Rcpp ;
+class Foo {
+ public:
+ Foo( double x_, double y_, double z_ ):
+ x(x_), y(y_), z(z_){}
+
+ double x ;
+ double y ;
+
+ double get_z(){ return z ; }
+ void set_z( double z_ ){ z = z_ ; }
+
+ private:
+ double z ;
+} ;
+
+RCPP_MODULE(mod_foo){
+ class_<Foo>( "Foo" )
+
+ .constructor<double,double,double>()
+
+ .field( "x", &Foo::x )
+ .field_readonly( "y", &Foo::y )
+
+ .property( "z", &Foo::get_z, &Foo::set_z )
+ ;
+}
+@
+
+The \texttt{.field} method exposes a public field with read/write access from R.
+\texttt{field} accepts an extra parameter to give a short description of the
+field:
+
+<<lang=cpp>>=
+ .field( "x", &Foo::x, "documentation for x" )
+@
+
+The \texttt{.field\_readonly} exposes a public field with read-only access from R.
+It also accepts the description of the field.
+
+<<lang=cpp>>=
+ .field_readonly( "y", &Foo::y, "documentation for y" )
+@
+
+The \texttt{.property} method allows indirect access to fields through
+a getter and a setter. The setter is optional, and the property is considered
+read-only if the setter is not supplied. Description of the property is also
+allowed:
+
+<<lang=cpp>>=
+ // with getter and setter
+ .property( "z", &Foo::get_z, &Foo::set_z, "Documentation for z" )
+
+ // with only getter
+ .property( "z", &Foo::get_z, "Documentation for z" )
+@
+
+The type of the field (\textbf{T}) is deduced from the return type of the getter, and if a
+setter is given its unique parameter should be of the same type.
+
+Getters can be member functions taking no parameter and returning a \textbf{T}
+(for example \texttt{get\_z} above), or
+a free function taking a pointer to the exposed
+class and returning a \textbf{T}, for example:
+
+<<lang=cpp>>=
+double z_get( Foo* foo ){ return foo->get_z() ; }
+@
+
+Setters can be either a member function taking a \texttt{T} and returning void, such
+as \texttt{set\_z} above, or a free function taking a pointer to the target
+class and a \textbf{T} :
+
+<<lang=cpp>>=
+void z_set( Foo* foo, double z ){ foo->set_z(z) ; }
+@
+
+Using properties give more flexibility in case field access has to be tracked
+or has impact on other fields. For example, this class keeps track of how many times
+the \texttt{x} field is read and written.
+
+<<lang=cpp>>=
+class Bar {
+ public:
+
+ Bar(double x_) : x(x_), nread(0), nwrite(0){}
+
+ double get_x( ){
+ nread++ ;
+ return x ;
+ }
+
+ void set_x( double x_){
+ nwrite++ ;
+ x = x_ ;
+ }
+
+ IntegerVector stats() const {
+ return IntegerVector::create(
+ _["read"] = nread,
+ _["write"] = nwrite
+ ) ;
+ }
+
+ private:
+ double x;
+ int nread, nwrite ;
+}
+RCPP_MODULE(mod_bar){
+ class_<Bar>( "Bar" )
+
+ .constructor<double>()
+
+ .property( "x", &Bar::get_x, &Bar::set_x )
+ .method( "stats", &Bar::stats )
+ ;
+}
+@
+<<echo=FALSE,results=hide>>=
+fx_bar <- cxxfunction( , "", includes = '
+class Bar {
+ public:
+
+ Bar(double x_) : x(x_), nread(0), nwrite(0){}
+
+ double get_x( ){
+ nread++ ;
+ return x ;
+ }
+
+ void set_x( double x_){
+ nwrite++ ;
+ x = x_ ;
+ }
+
+ IntegerVector stats() const {
+ return IntegerVector::create(
+ _["read"] = nread,
+ _["write"] = nwrite
+ ) ;
+ }
+
+ private:
+ double x;
+ int nread, nwrite ;
+} ;
+
+RCPP_MODULE(mod_bar){
+ class_<Bar>( "Bar" )
+
+ .constructor<double>()
+
+ .property( "x", &Bar::get_x, &Bar::set_x )
+ .method( "stats", &Bar::stats )
+ ;
+}
+', plugin = "Rcpp" )
+mod_bar <- Module( "mod_bar", getDynLib( fx_bar ) )
+@
+<<>>=
+Bar <- mod_bar$Bar
+b <- new( Bar, 10 )
+b$x + b$x
+b$stats()
+b$x <- 10
+b$stats()
+@
+
+
+\subsubsection{Exposing methods}
+
+
The construction of the object is then followed by two calls to the
\texttt{method} member function of \texttt{class\_<World>}. The
\texttt{method} methods can expose :
More information about the Rcpp-commits
mailing list