[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