[Rcpp-commits] r3898 - in pkg/Rcpp: . R src

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Tue Nov 6 15:05:24 CET 2012


Author: jjallaire
Date: 2012-11-06 15:05:23 +0100 (Tue, 06 Nov 2012)
New Revision: 3898

Modified:
   pkg/Rcpp/ChangeLog
   pkg/Rcpp/R/Attributes.R
   pkg/Rcpp/src/Attributes.cpp
Log:
use single module for exports

Modified: pkg/Rcpp/ChangeLog
===================================================================
--- pkg/Rcpp/ChangeLog	2012-11-05 19:55:56 UTC (rev 3897)
+++ pkg/Rcpp/ChangeLog	2012-11-06 14:05:23 UTC (rev 3898)
@@ -1,3 +1,8 @@
+2012-11-06  JJ Allaire <jj at rstudio.org>
+
+        * R/Attributes.R: use single module for exports
+        * src/Attributes.cpp: use single module for exports
+
 2012-11-05  Romain Francois <romain at r-enthusiasts.com>
 
         * include/Rcpp/Module.h: added class CppInheritedProperty to handle 

Modified: pkg/Rcpp/R/Attributes.R
===================================================================
--- pkg/Rcpp/R/Attributes.R	2012-11-05 19:55:56 UTC (rev 3897)
+++ pkg/Rcpp/R/Attributes.R	2012-11-06 14:05:23 UTC (rev 3898)
@@ -237,7 +237,7 @@
 .printVerboseOutput <- function(context) {
     
     cat("\nGenerated Rcpp module declaration:",
-        "\n--------------------------------------------------------\n")
+        "\n--------------------------------------------------------\n\n")
     cat(context$generatedCpp, sep="")
     
     cat("\nBuilding shared library", 

Modified: pkg/Rcpp/src/Attributes.cpp
===================================================================
--- pkg/Rcpp/src/Attributes.cpp	2012-11-05 19:55:56 UTC (rev 3897)
+++ pkg/Rcpp/src/Attributes.cpp	2012-11-06 14:05:23 UTC (rev 3898)
@@ -72,17 +72,7 @@
         time_t lastModified_;
     };
     
-    // Generate the preamble for a C++ file (headers)
-    std::string generateCppPreamble(const std::vector<std::string>& includes){
-        
-        std::ostringstream ostr;
-        for (std::size_t i=0;i<includes.size(); i++)
-            ostr << includes[i] << std::endl;
-        
-        return ostr.str();
-    }
-    
-    // Check if the passed attribute represents an exported function
+     // Check if the passed attribute represents an exported function
     bool isExportedFunction(const Attribute& attribute) {
         return (attribute.name() == kExportAttribute) &&
                !attribute.function().empty();
@@ -95,34 +85,41 @@
         else
             return attribute.function().name();
     }
- 
-    // Generate a module declaration
-    std::string generateCppModule(const std::string& moduleName, 
-                                  const SourceFileAttributes& attributes,
-                                  bool includeTypeInfo,
-                                  bool verbose) {
+    
+    // Generate the preamble for a C++ file (headers)
+    std::string generateCppPreamble(const std::vector<std::string>& includes,
+                                    const std::vector<std::string>& namespaces,
+                                    const std::vector<std::string>& prototypes){
         
         std::ostringstream ostr;
-           
-        // module header
-        ostr << std::endl << "// Module: " << moduleName << std::endl;  
         
-        // include namespace imports and function prototypes if requested
-        if (includeTypeInfo) {
-            
-            if (!attributes.namespaces().empty()) {
-                for (std::size_t i=0;i<attributes.namespaces().size(); i++)
-                    ostr << attributes.namespaces()[i] << std::endl;
-            }
+        if (!includes.empty()) {
+            for (std::size_t i=0;i<includes.size(); i++)
+                ostr << includes[i] << std::endl;
+            ostr << std::endl;
+        }
         
-            if (!attributes.prototypes().empty()) {
-                for (std::size_t i=0;i<attributes.prototypes().size(); i++)
-                    ostr << attributes.prototypes()[i] << ";" << std::endl;
-            }
+        if (!namespaces.empty()) {
+            for (std::size_t i=0;i<namespaces.size(); i++)
+                ostr << namespaces[i] << std::endl;
+            ostr << std::endl;
         }
         
-        // output the module
-        ostr << "RCPP_MODULE(" << moduleName  << ") {" << std::endl;
+        if (!prototypes.empty()) {
+            for (std::size_t i=0;i<prototypes.size(); i++)
+                ostr << prototypes[i] << ";" << std::endl;
+            ostr << std::endl;
+        }
+            
+        return ostr.str();
+    }
+    
+    
+    // Generate function entries for passed attributes
+    void generateCppModuleFunctions(std::ostream& ostr,
+                                    const SourceFileAttributes& attributes,
+                                    bool verbose)
+    {
         for(std::vector<Attribute>::const_iterator 
                 it = attributes.begin(); it != attributes.end(); ++it) {
             
@@ -140,11 +137,49 @@
                       
             } 
         }
+    }
+    
+    // Generate a module declaration
+   void generateCppModule(std::ostream& ostr,
+                          const std::string& moduleName, 
+                          const SourceFileAttributes& attributes,
+                          bool verbose) {    
+        ostr << "RCPP_MODULE(" << moduleName  << ") {" << std::endl;
+        generateCppModuleFunctions(ostr, attributes, verbose);
         ostr << "}" << std::endl;
-        
-        return ostr.str();    
     }    
     
+    // Generate placeholder function declaration (for roxygen)
+    void generateRoxygenPlaceholder(std::ostream& ostr,
+                                    const Attribute& attribute) {
+        
+        ostr << exportedName(attribute) << "<- function(";
+        const std::vector<Argument>& args = attribute.function().arguments();
+        for (std::size_t i=0; i<args.size(); i++) {
+            ostr << args[i].name();
+            if (i != (args.size()-1))
+                ostr << ", ";
+        }
+        ostr << ") {}" << std::endl;
+    }
+    
+    // Generate roxygen
+    void generateRoxygen(std::ostream& ostr,
+                         const SourceFileAttributes& attributes) {
+        
+        for(std::vector<Attribute>::const_iterator 
+                it = attributes.begin(); it != attributes.end(); ++it) {
+         
+            if (isExportedFunction(*it) && !it->roxygen().empty()) {
+                ostr << std::endl;
+                for (std::size_t i=0; i<it->roxygen().size(); i++)
+                    ostr << it->roxygen()[i] << std::endl;
+                generateRoxygenPlaceholder(ostr, *it);
+                ostr << std::endl;
+            } 
+        }
+    }
+    
     // Class that manages generation of source code for the sourceCpp dynlib
     class SourceCppDynlib {
     public:
@@ -214,10 +249,9 @@
             SourceFileAttributes sourceAttributes(cppSourcePath_);
         
             // generate RCPP module
-            generatedCpp_ = generateCppModule(moduleName(), 
-                                              sourceAttributes, 
-                                              false,    // no typeinfo 
-                                              false);   // not verbose
+            std::ostringstream ostr;
+            generateCppModule(ostr, moduleName(), sourceAttributes, false); 
+            generatedCpp_ = ostr.str();
             
             // open source file and append module
             std::ofstream cppOfs(generatedCppSourcePath().c_str(), 
@@ -388,6 +422,11 @@
             return codeStream_;
         }
         
+        // Covert to ostream
+        operator std::ostream&() {
+            return codeStream_;
+        }
+        
         // Commit the stream -- is a no-op if the existing code is identical
         // to the generated code. Returns true if data was written and false
         // if it wasn't (throws exception on io error)
@@ -408,7 +447,7 @@
             headerStream << commentPrefix_ << " Generator token: " 
                          << generatorToken() << std::endl << std::endl;      
             if (!preamble.empty())
-                headerStream << preamble << std::endl;
+                headerStream << preamble;
                 
             // get generated code and only write it if there was a change
             std::string generatedCode = headerStream.str() + code;        
@@ -549,17 +588,23 @@
     bool verbose = Rcpp::as<bool>(sVerbose);
     Rcpp::List platform = Rcpp::as<Rcpp::List>(sPlatform);
      
-    // Establish stream for Cpp code
+    // establish stream for Cpp code as well as vectors to collect
+    // namespaces and function prototypes
     std::string fileSep = Rcpp::as<std::string>(platform["file.sep"]);
     std::string cppExportsFile = packageDir + fileSep + "src" + 
                                  fileSep + "RcppExports.cpp";
     CppExportsStream cppStream(cppExportsFile);
+    std::vector<std::string> namespaces;
+    std::vector<std::string> prototypes;
     
-    // Establish stream for R code
+    // establish stream for R code
     std::string rExportsFile = packageDir + fileSep + "R" + 
                                fileSep + "RcppExports.R";
     RExportsStream rStream(rExportsFile);
      
+    // start Rcpp module
+    cppStream << "RCPP_MODULE(RcppExports) {" << std::endl;
+    
     // Parse attributes from each file and generate code as required. 
     for (std::size_t i=0; i<cppFiles.size(); i++) {
         
@@ -573,21 +618,43 @@
         if (!attributes.empty() && verbose)
             Rcpp::Rcout << "Exports from " << cppFile << ":" << std::endl;
         
-        // generate C++ module
-        std::string moduleName = "RcppExports_" + cppFileBasenames[i];
-        cppStream << generateCppModule(moduleName, attributes, true, verbose);
+        // generate functions
+        generateCppModuleFunctions(cppStream, attributes, verbose);
         
-        // genereate R loadModule 
-        rStream << "loadModule(\"" << moduleName << "\", what = TRUE)" 
-                << std::endl;
-      
+        // copy namespaces and prototypes
+        std::copy(attributes.namespaces().begin(),
+                  attributes.namespaces().end(),
+                  std::back_inserter(namespaces));
+        std::copy(attributes.prototypes().begin(),
+                  attributes.prototypes().end(),
+                  std::back_inserter(prototypes));
+        
+        // generate roxygen placeholders
+        generateRoxygen(rStream, attributes);
+        
         // verbose if requested
         if (!attributes.empty() && verbose)
             Rcpp::Rcout << std::endl;
     }
-                           
-    // commit the code
-    bool wroteCpp = cppStream.commit(generateCppPreamble(includes));     
+    
+    // end Rcpp module
+    cppStream << "}" << std::endl;
+          
+    // eliminate namespace duplicates
+    std::sort(namespaces.begin(), namespaces.end());
+    std::vector<std::string>::const_iterator it = 
+                        std::unique(namespaces.begin(), namespaces.end());
+    namespaces.resize( it - namespaces.begin());
+          
+    // commit the C++ code
+    bool wroteCpp = cppStream.commit(generateCppPreamble(includes, 
+                                                         namespaces, 
+                                                         prototypes));     
+                                                         
+    // add loadModule call for R
+    rStream << "Rcpp::loadModule(\"RcppExports\", what = TRUE)" << std::endl;
+             
+    // commit the R code
     bool wroteR = rStream.commit();
     
     // verbose outputs



More information about the Rcpp-commits mailing list