[Rcpp-commits] r3899 - in pkg/Rcpp: . src
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Tue Nov 6 16:24:58 CET 2012
Author: jjallaire
Date: 2012-11-06 16:24:58 +0100 (Tue, 06 Nov 2012)
New Revision: 3899
Modified:
pkg/Rcpp/ChangeLog
pkg/Rcpp/src/Attributes.cpp
Log:
refectored attribute code generators for improved extensiblity
Modified: pkg/Rcpp/ChangeLog
===================================================================
--- pkg/Rcpp/ChangeLog 2012-11-06 14:05:23 UTC (rev 3898)
+++ pkg/Rcpp/ChangeLog 2012-11-06 15:24:58 UTC (rev 3899)
@@ -1,7 +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
+ * R/Attributes.R: tweak whitespace in verbose mode
+ * src/Attributes.cpp: refactor code generators; use single module
+ for exports
2012-11-05 Romain Francois <romain at r-enthusiasts.com>
Modified: pkg/Rcpp/src/Attributes.cpp
===================================================================
--- pkg/Rcpp/src/Attributes.cpp 2012-11-06 14:05:23 UTC (rev 3898)
+++ pkg/Rcpp/src/Attributes.cpp 2012-11-06 15:24:58 UTC (rev 3899)
@@ -86,35 +86,6 @@
return attribute.function().name();
}
- // 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;
-
- if (!includes.empty()) {
- for (std::size_t i=0;i<includes.size(); i++)
- ostr << includes[i] << std::endl;
- ostr << std::endl;
- }
-
- if (!namespaces.empty()) {
- for (std::size_t i=0;i<namespaces.size(); i++)
- ostr << namespaces[i] << std::endl;
- ostr << 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,
@@ -387,11 +358,11 @@
std::vector<Entry> entries_;
};
- // Class which manages writing of code for compileAttributes
- class ExportsStream {
- public:
- ExportsStream(const std::string& targetFile,
- const std::string& commentPrefix)
+ // Abstract class which manages writing of code for compileAttributes
+ class ExportsGenerator {
+ protected:
+ ExportsGenerator(const std::string& targetFile,
+ const std::string& commentPrefix)
: targetFile_(targetFile), commentPrefix_(commentPrefix) {
// read the existing target file if it exists
@@ -408,25 +379,39 @@
if (!isSafeToOverwrite())
throw Rcpp::file_exists(targetFile_);
}
-
+
private:
// prohibit copying
- ExportsStream(const ExportsStream&);
- ExportsStream& operator=(const ExportsStream&);
+ ExportsGenerator(const ExportsGenerator&);
+ ExportsGenerator& operator=(const ExportsGenerator&);
public:
- // Stream code into the buffer
- template <typename T>
- std::ostream& operator<<(const T& data) {
- codeStream_ << data;
- return codeStream_;
+ virtual ~ExportsGenerator() {}
+
+ // Abstract interface for code generation
+ virtual void writeBegin() {}
+ virtual void writeFunctions(const SourceFileAttributes &attributes,
+ bool verbose) {}
+ virtual void writeEnd() {}
+
+ virtual bool commit(const std::vector<std::string>& includes,
+ const std::vector<std::string>& namespaces,
+ const std::vector<std::string>& prototypes) {
+ return commit();
}
- // Covert to ostream
+ // Allow generator to appear as a std::ostream&
operator std::ostream&() {
return codeStream_;
}
+ protected:
+
+ // Allow access to the output stream
+ std::ostream& ostr() {
+ 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)
@@ -490,21 +475,154 @@
std::ostringstream codeStream_;
};
- class CppExportsStream : public ExportsStream {
+
+ // Class which manages generating RcppExports.cpp
+ class CppExportsGenerator : public ExportsGenerator {
public:
- explicit CppExportsStream(const std::string& targetFile)
- : ExportsStream(targetFile, "//")
+ explicit CppExportsGenerator(const std::string& packageDir,
+ const std::string& fileSep)
+ : ExportsGenerator(
+ packageDir + fileSep + "src" + fileSep + "RcppExports.cpp",
+ "//")
{
}
+
+ virtual void writeBegin() {
+ ostr() << "RCPP_MODULE(RcppExports) {" << std::endl;
+ }
+
+ virtual void writeFunctions(const SourceFileAttributes &attributes,
+ bool verbose) {
+ // verbose output if requested
+ if (verbose) {
+ Rcpp::Rcout << "Exports from " << attributes.sourceFile() << ":"
+ << std::endl;
+ }
+
+ // generate functions
+ generateCppModuleFunctions(ostr(), attributes, verbose);
+
+ // verbose if requested
+ if (verbose)
+ Rcpp::Rcout << std::endl;
+ }
+
+ virtual void writeEnd() {
+ ostr() << "}" << std::endl;
+ }
+
+ virtual bool commit(const std::vector<std::string>& includes,
+ const std::vector<std::string>& namespaces,
+ const std::vector<std::string>& prototypes) {
+
+ // generate preamble
+ std::ostringstream ostr;
+ if (!includes.empty()) {
+ for (std::size_t i=0;i<includes.size(); i++)
+ ostr << includes[i] << std::endl;
+ ostr << std::endl;
+ }
+
+ if (!namespaces.empty()) {
+ for (std::size_t i=0;i<namespaces.size(); i++)
+ ostr << namespaces[i] << std::endl;
+ ostr << std::endl;
+ }
+
+ if (!prototypes.empty()) {
+ for (std::size_t i=0;i<prototypes.size(); i++)
+ ostr << prototypes[i] << ";" << std::endl;
+ ostr << std::endl;
+ }
+
+ // commit with preamble
+ return ExportsGenerator::commit(ostr.str());
+
+ }
+
};
- class RExportsStream : public ExportsStream {
+ // Class which manages generator RcppExports.R
+ class RExportsGenerator : public ExportsGenerator {
public:
- explicit RExportsStream(const std::string& targetFile)
- : ExportsStream(targetFile, "#")
+ explicit RExportsGenerator(const std::string& packageDir,
+ const std::string& fileSep)
+ : ExportsGenerator(
+ packageDir + fileSep + "R" + fileSep + "RcppExports.R",
+ "#")
{
}
+
+ virtual void writeFunctions(const SourceFileAttributes &attributes,
+ bool verbose) {
+ // generate roxygen placeholders
+ generateRoxygen(ostr(), attributes);
+ }
+
+ virtual void writeEnd() {
+ ostr() << "Rcpp::loadModule(\"RcppExports\", what = TRUE)"
+ << std::endl;
+ }
};
+
+ // Class to manage and dispatch to a list of generators
+ class ExportsGenerators {
+ public:
+ typedef std::vector<ExportsGenerator*>::iterator Itr;
+
+ ExportsGenerators() {}
+
+ virtual ~ExportsGenerators() {
+ try {
+ for(Itr it = generators_.begin(); it != generators_.end(); ++it)
+ delete *it;
+ generators_.clear();
+ }
+ catch(...) {}
+ }
+
+ void add(ExportsGenerator* pGenerator) {
+ generators_.push_back(pGenerator);
+ }
+
+ void writeBegin() {
+ for(Itr it = generators_.begin(); it != generators_.end(); ++it)
+ (*it)->writeBegin();
+ }
+
+ void writeFunctions(const SourceFileAttributes &attributes,
+ bool verbose) {
+ for(Itr it = generators_.begin(); it != generators_.end(); ++it)
+ (*it)->writeFunctions(attributes, verbose);
+ }
+
+ void writeEnd() {
+ for(Itr it = generators_.begin(); it != generators_.end(); ++it)
+ (*it)->writeEnd();
+ }
+
+ bool commit(const std::vector<std::string>& includes,
+ const std::vector<std::string>& namespaces,
+ const std::vector<std::string>& prototypes) {
+
+ bool wrote = false;
+
+ for(Itr it = generators_.begin(); it != generators_.end(); ++it) {
+ if ((*it)->commit(includes, namespaces, prototypes))
+ wrote = true;
+ }
+
+ return wrote;
+ }
+
+ private:
+ // prohibit copying
+ ExportsGenerators(const ExportsGenerators&);
+ ExportsGenerators& operator=(const ExportsGenerators&);
+
+ private:
+ std::vector<ExportsGenerator*> generators_;
+ };
} // anonymous namespace
@@ -587,24 +705,18 @@
Rcpp::as<std::vector<std::string> >(sIncludes);
bool verbose = Rcpp::as<bool>(sVerbose);
Rcpp::List platform = Rcpp::as<Rcpp::List>(sPlatform);
+ std::string fileSep = Rcpp::as<std::string>(platform["file.sep"]);
- // 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);
+ // initialize generators and namespace/prototype vectors
+ ExportsGenerators generators;
+ generators.add(new CppExportsGenerator(packageDir, fileSep));
+ generators.add(new RExportsGenerator(packageDir, fileSep));
std::vector<std::string> namespaces;
std::vector<std::string> prototypes;
- // establish stream for R code
- std::string rExportsFile = packageDir + fileSep + "R" +
- fileSep + "RcppExports.R";
- RExportsStream rStream(rExportsFile);
+ // write begin
+ generators.writeBegin();
- // 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++) {
@@ -613,14 +725,7 @@
SourceFileAttributes attributes(cppFile);
if (attributes.empty())
continue;
-
- // verbose output if requested
- if (!attributes.empty() && verbose)
- Rcpp::Rcout << "Exports from " << cppFile << ":" << std::endl;
-
- // generate functions
- generateCppModuleFunctions(cppStream, attributes, verbose);
-
+
// copy namespaces and prototypes
std::copy(attributes.namespaces().begin(),
attributes.namespaces().end(),
@@ -629,44 +734,31 @@
attributes.prototypes().end(),
std::back_inserter(prototypes));
- // generate roxygen placeholders
- generateRoxygen(rStream, attributes);
-
- // verbose if requested
- if (!attributes.empty() && verbose)
- Rcpp::Rcout << std::endl;
+ // write functions
+ generators.writeFunctions(attributes, verbose);
}
- // end Rcpp module
- cppStream << "}" << std::endl;
-
+ // write end
+ generators.writeEnd();
+
// 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
+ // commit
+ bool wrote = generators.commit(includes, namespaces, prototypes);
+
+ // verbose output
if (verbose) {
- Rcpp::Rcout << "Generating exports files:" << std::endl;
- Rcpp::Rcout << " RcppExports.cpp (" <<
- (wroteCpp ? "updated" : "already up to date") << ")" << std::endl;
- Rcpp::Rcout << " RcppExports.R (" <<
- (wroteR ? "updated" : "already up to date") << ")" << std::endl;
+ if (wrote)
+ Rcpp::Rcout << "Rcpp exports files updated" << std::endl;
+ else
+ Rcpp::Rcout << "Rcpp exports files already up to date" << std::endl;
}
// return status
- return Rcpp::wrap(wroteCpp || wroteR);
+ return Rcpp::wrap<bool>(wrote);
END_RCPP
}
More information about the Rcpp-commits
mailing list