[Rcpp-commits] r4272 - in pkg/Rcpp: . R inst man src

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Sun Feb 24 13:09:03 CET 2013


Author: jjallaire
Date: 2013-02-24 13:09:02 +0100 (Sun, 24 Feb 2013)
New Revision: 4272

Modified:
   pkg/Rcpp/ChangeLog
   pkg/Rcpp/R/Attributes.R
   pkg/Rcpp/inst/NEWS.Rd
   pkg/Rcpp/man/sourceCpp.Rd
   pkg/Rcpp/src/attributes.cpp
Log:
support for Rcpp modules in sourceCpp

Modified: pkg/Rcpp/ChangeLog
===================================================================
--- pkg/Rcpp/ChangeLog	2013-02-24 10:10:45 UTC (rev 4271)
+++ pkg/Rcpp/ChangeLog	2013-02-24 12:09:02 UTC (rev 4272)
@@ -1,7 +1,9 @@
 2013-02-24 JJ Allaire <jj at rstudio.org>
 
         * R/Attributes.R: add global package include file to RcppExports.cpp
-        if it exists
+        if it exists; handle Rcpp module definitions in sourceCpp
+        * src/attributes.cpp: handle Rcpp module definitions in sourceCpp
+        * man/sourceCpp.Rd: documentation updates
 
 2013-02-19 Romain Francois <romain at r-enthusiasts.com>
 

Modified: pkg/Rcpp/R/Attributes.R
===================================================================
--- pkg/Rcpp/R/Attributes.R	2013-02-24 10:10:45 UTC (rev 4271)
+++ pkg/Rcpp/R/Attributes.R	2013-02-24 12:09:02 UTC (rev 4272)
@@ -141,19 +141,21 @@
                 "force a rebuild)\n\n", sep="")
     }
     
-    # load the module if we have exported functions (else there is no module)
-    if (length(context$exportedFunctions) > 0) {
+    # load the module if we have exported symbols
+    if (length(context$exportedFunctions) > 0 || length(context$modules) > 0) {
         
         # remove existing objects of the same name from the environment
-        exports <- context$exportedFunctions
+        exports <- c(context$exportedFunctions, context$modules)
         removeObjs <- exports[exports %in% ls(envir = env, all.names = T)]
         remove(list = removeObjs, envir = env)
         
         # source the R script
         scriptPath <- file.path(context$buildDirectory, context$rSourceFilename) 
         source(scriptPath, local = env)
+        
     } else if (getOption("rcpp.warnNoExports", default=TRUE)) {
-        warning("No Rcpp::export attributes found in source")
+        warning("No Rcpp::export attributes or RCPP_MODULE declarations ",
+                "found in source")
     }
     
     # source the embeddedR
@@ -162,8 +164,9 @@
         source(file=srcConn, echo=TRUE)
     }
     
-    # return (invisibly) a list of exported functions
-    invisible(context$exportedFunctions)
+    # return (invisibly) a list containing exported functions and modules
+    invisible(list(functions = context$exportedFunctions,
+                   modules = context$modules))
 }
 
 # Define a single C++ function
@@ -233,12 +236,12 @@
                           verbose = verbose)
     
     # verify that a single function was exported and return it
-    if (length(exported) == 0)
+    if (length(exported$functions) == 0)
         stop("No function definition found")
-    else if (length(exported) > 1)
+    else if (length(exported$functions) > 1)
         stop("More than one function definition")
     else {
-        functionName <- exported[[1]]
+        functionName <- exported$functions[[1]]
         invisible(get(functionName, env))
     }
 }

Modified: pkg/Rcpp/inst/NEWS.Rd
===================================================================
--- pkg/Rcpp/inst/NEWS.Rd	2013-02-24 10:10:45 UTC (rev 4271)
+++ pkg/Rcpp/inst/NEWS.Rd	2013-02-24 12:09:02 UTC (rev 4272)
@@ -12,6 +12,7 @@
     }
     \item Changes in Rcpp attributes: 
     \itemize{
+        \item Rcpp modules can now be used with \code{sourceCpp}
         \item Added \code{Rcpp::plugins} attribute for binding 
         directly to inline plugins. Plugins can be registered using
         the new \code{registerPlugin} function.

Modified: pkg/Rcpp/man/sourceCpp.Rd
===================================================================
--- pkg/Rcpp/man/sourceCpp.Rd	2013-02-24 10:10:45 UTC (rev 4271)
+++ pkg/Rcpp/man/sourceCpp.Rd	2013-02-24 12:09:02 UTC (rev 4272)
@@ -4,7 +4,8 @@
 Source C++ Code from a File or String
 }
 \description{
-\code{sourceCpp} parses the specified C++ file or source code and looks for functions marked with the \code{\link[=exportAttribute]{Rcpp::export}} attribute. A shared library is then built and its exported functions are made available as R functions in the specified environment.
+\code{sourceCpp} parses the specified C++ file or source code and looks for functions marked with the \code{\link[=exportAttribute]{Rcpp::export}} attribute
+and RCPP_MODULE declarations. A shared library is then built and its exported functions and Rcpp modules are made available in the specified environment.
 }
 \usage{
 sourceCpp(file = "", code = NULL, env = globalenv(), 
@@ -20,7 +21,7 @@
     A character string with source code. If supplied, the code is taken from this string instead of a file. 
 }
   \item{env}{
-    Environment where the R functions should be made available.
+    Environment where the R functions and modules should be made available.
 }
   \item{rebuild}{
     Force a rebuild of the shared library.
@@ -37,6 +38,8 @@
 
     Functions exported using \code{sourceCpp} must meet several conditions, including being defined in the global namespace and having return types that are compatible with \code{Rcpp::wrap} and parameter types that are compatible with \code{Rcpp::as}. See the \code{\link[=exportAttribute]{Rcpp::export}} documentation for more details.
     
+    Rcpp Modules will be automatically loaded into the specified environment using the \code{\link[=Module]{Module}} function. the name of the loaded module object will be the same as the name specified in the \code{RCPP_MODULE} declaration.
+    
     If the source file has compilation dependencies on other packages (e.g. \pkg{Matrix}, \pkg{RcppArmadillo}) then an \code{\link[=dependsAttribute]{Rcpp::depends}} attribute should be provided naming these dependencies. 
     
 	It's possible to embed chunks of R code within a C++ source file by including the R code within a block comment with the prefix of \code{/*** R}. For example:
@@ -50,11 +53,15 @@
 */
 }
 
-	Multiple R code chunks can be included in a C++ file. All R code is sourced after the C++ functions within the file have been defined.  
+	Multiple R code chunks can be included in a C++ file. R code is sourced after the C++ compliation is completed so all functions and modules will be available to the R code.   
 }
 
 \value{
-    Returns (invisibly) a character vector with the names of the R functions that were sourced into the specified environment.
+    Returns (invisibly) a list with two elements: 
+    \tabular{ll}{
+        \code{functions} \tab Names of exported functions\cr
+        \code{modules} \tab Names of Rcpp modules\cr
+    }
 }
 
 \note{
@@ -64,7 +71,7 @@
     
     If you are sourcing a C++ file from within the \code{src} directory of a package then the package's \code{LinkingTo} dependencies, \code{inst/include}, and \code{src} directories are automatically included in the compilation.
     
-    If no \code{Rcpp::export} attributes are found within the source file then a warning is printed to the console. You can disable this warning by setting the \code{rcpp.warnNoExports} option to \code{FALSE}.
+    If no \code{Rcpp::export} attributes or \code{RCPP_MODULE} declarations are found within the source file then a warning is printed to the console. You can disable this warning by setting the \code{rcpp.warnNoExports} option to \code{FALSE}.
 
 }
 

Modified: pkg/Rcpp/src/attributes.cpp
===================================================================
--- pkg/Rcpp/src/attributes.cpp	2013-02-24 10:10:45 UTC (rev 4271)
+++ pkg/Rcpp/src/attributes.cpp	2013-02-24 12:09:02 UTC (rev 4272)
@@ -258,10 +258,14 @@
         virtual ~SourceFileAttributes() {};
         virtual const std::string& sourceFile() const = 0;
         virtual bool hasInterface(const std::string& name) const = 0;
+     
         typedef std::vector<Attribute>::const_iterator const_iterator;
         virtual const_iterator begin() const = 0;
         virtual const_iterator end() const = 0;
-        virtual bool empty() const = 0;  
+        
+        virtual const std::vector<std::string>& modules() const = 0;
+    
+        virtual bool hasAttributesOrModules() const = 0;  
     };
     
 
@@ -288,6 +292,7 @@
     public:
         bool inComment() const { return inComment_; }
         void submitLine(const std::string& line); 
+        void reset() { inComment_ = false; }
     private:
         bool inComment_;
     };
@@ -309,7 +314,17 @@
         }
         virtual const_iterator begin() const { return attributes_.begin(); }
         virtual const_iterator end() const { return attributes_.end(); }
-        virtual bool empty() const { return attributes_.empty(); }
+        
+        virtual const std::vector<std::string>& modules() const
+        {
+            return modules_;
+        }
+        
+        virtual bool hasAttributesOrModules() const 
+        { 
+            return !attributes_.empty() || !modules_.empty(); 
+        }
+        
         virtual bool hasInterface(const std::string& name) const {
             
             for (const_iterator it=begin(); it != end(); ++it) {
@@ -358,6 +373,7 @@
         std::string sourceFile_;
         CharacterVector lines_;
         std::vector<Attribute> attributes_;
+        std::vector<std::string> modules_;
         std::vector<std::string> embeddedR_;
         std::vector<std::string> roxygenBuffer_;
     };
@@ -795,7 +811,8 @@
         std::string contents = buffer.str();
         
         // Check for attribute signature
-        if (contents.find("[[Rcpp::") != std::string::npos) { 
+        if (contents.find("[[Rcpp::") != std::string::npos ||
+            contents.find("RCPP_MODULE") != std::string::npos) { 
             
             // Now read into a list of strings (which we can pass to regexec)
             // First read into a std::deque (which will handle lots of append
@@ -850,6 +867,26 @@
                 } 
             }
             
+             // Scan for Rcpp modules 
+            commentState.reset();
+            Rcpp::List modMatches = regexMatches(lines_, 
+                "^\\s*RCPP_MODULE\\s*\\(\\s*(\\w+)\\s*\\).*$");
+            for (int i = 0; i<modMatches.size(); i++) {   
+                
+                // track whether we are in a comment and bail if we are in one
+                std::string line = lines[i];
+                commentState.submitLine(line);
+                if (commentState.inComment())
+                    continue;
+                
+                // get the module declaration
+                Rcpp::CharacterVector match = modMatches[i];
+                if (match.size() > 0) {
+                    const char * name = match[1];
+                    modules_.push_back(name);
+                }
+            }
+            
             // Parse embedded R
             embeddedR_ = parseEmbeddedR(lines_, lines);
         }       
@@ -2331,7 +2368,7 @@
      
             rOfs.close();
                
-            // discover exported functions, and dependencies
+            // discover exported functions and dependencies
             exportedFunctions_.clear();
             depends_.clear();
             plugins_.clear();
@@ -2352,6 +2389,9 @@
                  }
             }
             
+            // capture modules
+            modules_ = sourceAttributes.modules();
+            
             // capture embededded R
             embeddedR_ = sourceAttributes.embeddedR();
         }
@@ -2399,6 +2439,10 @@
             return exportedFunctions_;
         }
         
+        const std::vector<std::string>& modules() const {
+            return modules_;
+        }
+        
         const std::vector<std::string>& depends() const { return depends_; };
         
         const std::vector<std::string>& plugins() const { return plugins_; };
@@ -2437,7 +2481,23 @@
                      << dllInfo << ", " 
                      << "'" << contextId_ + "_" + function.name() 
                      << "')" << std::endl;
-            }        
+            }   
+            
+            // modules
+            std::vector<std::string> modules = attributes.modules();
+            if (modules.size() > 0)
+            {
+                // modules require definition of C++Object to be loaded
+                ostr << "library(Rcpp)" << std::endl;
+                
+                // load each module
+                for (std::vector<std::string>::const_iterator 
+                    it = modules.begin(); it != modules.end(); ++it)
+                {
+                    ostr << *it << " <- Rcpp::Module(\"" << *it << "\"," 
+                         << dllInfo << ")" << std::endl;
+                }
+            }
                            
         }
         
@@ -2459,6 +2519,7 @@
         std::string previousDynlibFilename_;
         std::string dynlibExt_;
         std::vector<std::string> exportedFunctions_;
+        std::vector<std::string> modules_;
         std::vector<std::string> depends_;
         std::vector<std::string> plugins_;
         std::vector<std::string> embeddedR_;
@@ -2576,6 +2637,7 @@
         _["buildDirectory"] = pDynlib->buildDirectory(),
         _["generatedCpp"] = pDynlib->generatedCpp(),
         _["exportedFunctions"] = pDynlib->exportedFunctions(),
+        _["modules"] = pDynlib->modules(),
         _["cppSourceFilename"] = pDynlib->cppSourceFilename(),
         _["rSourceFilename"] = pDynlib->rSourceFilename(),
         _["dynlibFilename"] = pDynlib->dynlibFilename(),
@@ -2658,7 +2720,7 @@
         // parse attributes (continue if there are none)
         std::string cppFile = cppFiles[i];
         SourceFileAttributesParser attributes(cppFile);
-        if (attributes.empty())
+        if (!attributes.hasAttributesOrModules())
             continue;
             
         // confirm we have attributes



More information about the Rcpp-commits mailing list