[Rcpp-commits] r4150 - in pkg/Rcpp: . src
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Tue Dec 11 16:27:19 CET 2012
Author: jjallaire
Date: 2012-12-11 16:27:18 +0100 (Tue, 11 Dec 2012)
New Revision: 4150
Added:
pkg/Rcpp/src/attributes.cpp
Removed:
pkg/Rcpp/src/Attributes.cpp
pkg/Rcpp/src/AttributesGen.cpp
pkg/Rcpp/src/AttributesGen.h
pkg/Rcpp/src/AttributesParser.cpp
pkg/Rcpp/src/AttributesParser.h
pkg/Rcpp/src/AttributesTypes.h
pkg/Rcpp/src/AttributesUtil.h
Modified:
pkg/Rcpp/ChangeLog
Log:
consolidate attributes into single file
Modified: pkg/Rcpp/ChangeLog
===================================================================
--- pkg/Rcpp/ChangeLog 2012-12-11 15:21:06 UTC (rev 4149)
+++ pkg/Rcpp/ChangeLog 2012-12-11 15:27:18 UTC (rev 4150)
@@ -1,6 +1,14 @@
2012-12-11 JJ Allaire <jj at rstudio.org>
* R/Attributes.R: always print output when shared library is not created
+ * src/attributes.cpp: consolidate attributes into single file
+ * src/Attributes.cpp: consolidate attributes into single file
+ * src/AttributesGen.h: consolidate attributes into single file
+ * src/AttributesGen.cpp: consolidate attributes into single file
+ * src/AttributesParser.h: consolidate attributes into single file
+ * src/AttributesParser.cpp: consolidate attributes into single file
+ * src/AttributesTypes.h: consolidate attributes into single file
+ * src/AttributesUtil.h: consolidate attributes into single file
2012-12-11 Romain Francois <romain at r-enthusiasts.com>
Deleted: pkg/Rcpp/src/Attributes.cpp
===================================================================
--- pkg/Rcpp/src/Attributes.cpp 2012-12-11 15:21:06 UTC (rev 4149)
+++ pkg/Rcpp/src/Attributes.cpp 2012-12-11 15:27:18 UTC (rev 4150)
@@ -1,614 +0,0 @@
-// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
-//
-// Attributes.cpp: Rcpp R/C++ interface class library -- Rcpp attributes
-//
-// Copyright (C) 2012 JJ Allaire, Dirk Eddelbuettel and Romain Francois
-//
-// This file is part of Rcpp.
-//
-// Rcpp is free software: you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 2 of the License, or
-// (at your option) any later version.
-//
-// Rcpp is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#include <fstream>
-#include <cstring>
-#include <map>
-#include <set>
-#include <algorithm>
-
-#define RCPP_NO_SUGAR
-#include <Rcpp.h>
-
-#include "AttributesGen.h"
-#include "AttributesParser.h"
-#include "AttributesUtil.h"
-
-// provide implementations for util
-namespace Rcpp {
-namespace attributes {
-
- // Utility class for getting file existence and last modified time
- FileInfo::FileInfo(const std::string& path)
- : path_(path), exists_(false), lastModified_(0)
- {
- #ifdef _WIN32
- struct _stat buffer;
- int result = _stat(path.c_str(), &buffer);
- #else
- struct stat buffer;
- int result = stat(path.c_str(), &buffer);
- #endif
- if (result != 0) {
- if (errno == ENOENT)
- exists_ = false;
- else
- throw Rcpp::file_io_error(errno, path);
- } else {
- exists_ = true;
- lastModified_ = buffer.st_mtime;
- }
- }
-
- // Remove a file (call back into R for this)
- bool removeFile(const std::string& path) {
- if (FileInfo(path).exists()) {
- Rcpp::Function rm = Rcpp::Environment::base_env()["file.remove"];
- rm(path);
- return true;
- }
- else {
- return false;
- }
- }
-
- // Recursively create a directory (call back into R for this)
- void createDirectory(const std::string& path) {
- if (!FileInfo(path).exists()) {
- Rcpp::Function mkdir = Rcpp::Environment::base_env()["dir.create"];
- mkdir(path, Rcpp::Named("recursive") = true);
- }
- }
-
- // Known whitespace chars
- const char * const kWhitespaceChars = " \f\n\r\t\v";
-
- // Query whether a character is whitespace
- bool isWhitespace(char ch) {
- return std::strchr(kWhitespaceChars, ch) != NULL;
- }
-
- // Trim a string
- void trimWhitespace(std::string* pStr) {
-
- // skip empty case
- if (pStr->empty())
- return;
-
- // trim right
- std::string::size_type pos = pStr->find_last_not_of(kWhitespaceChars);
- if (pos != std::string::npos)
- pStr->erase(pos + 1);
-
- // trim left
- pos = pStr->find_first_not_of(kWhitespaceChars);
- pStr->erase(0, pos);
- }
-
- // Strip balanced quotes from around a string (assumes already trimmed)
- void stripQuotes(std::string* pStr) {
- if (pStr->length() < 2)
- return;
- char quote = *(pStr->begin());
- if ( (quote == '\'' || quote == '\"') && (*(pStr->rbegin()) == quote) )
- *pStr = pStr->substr(1, pStr->length()-2);
- }
-
- // is the passed string quoted?
- bool isQuoted(const std::string& str) {
- if (str.length() < 2)
- return false;
- char quote = *(str.begin());
- return (quote == '\'' || quote == '\"') && (*(str.rbegin()) == quote);
- }
-
- // show a warning message
- void showWarning(const std::string& msg) {
- Rcpp::Function warning = Rcpp::Environment::base_env()["warning"];
- warning(msg, Rcpp::Named("call.") = false);
- }
-
-} // namespace attributes
-} // namespace Rcpp
-
-
-using namespace Rcpp::attributes;
-
-// Implementation helpers for sourceCppContext
-namespace {
-
- // Class that manages generation of source code for the sourceCpp dynlib
- class SourceCppDynlib {
- public:
- SourceCppDynlib() {}
-
- SourceCppDynlib(const std::string& cppSourcePath, Rcpp::List platform)
- : cppSourcePath_(cppSourcePath)
-
- {
- // get cpp source file info
- FileInfo cppSourceFilenameInfo(cppSourcePath_);
- if (!cppSourceFilenameInfo.exists())
- throw Rcpp::file_not_found(cppSourcePath_);
-
- // record the base name of the source file
- Rcpp::Function basename = Rcpp::Environment::base_env()["basename"];
- cppSourceFilename_ = Rcpp::as<std::string>(basename(cppSourcePath_));
-
- // get platform info
- fileSep_ = Rcpp::as<std::string>(platform["file.sep"]);
- dynlibExt_ = Rcpp::as<std::string>(platform["dynlib.ext"]);
-
- // generate temp directory
- Rcpp::Function tempfile = Rcpp::Environment::base_env()["tempfile"];
- buildDirectory_ = Rcpp::as<std::string>(tempfile("sourcecpp_"));
- std::replace(buildDirectory_.begin(), buildDirectory_.end(), '\\', '/');
- Rcpp::Function dircreate = Rcpp::Environment::base_env()["dir.create"];
- dircreate(buildDirectory_);
-
- // generate a random context id
- contextId_ = "sourceCpp_" + createRandomizer();
-
- // regenerate the source code
- regenerateSource();
- }
-
- bool isEmpty() const { return cppSourcePath_.empty(); }
-
- bool isBuilt() const { return FileInfo(dynlibPath()).exists(); };
-
- bool isSourceDirty() const {
- // source file out of date means we're dirty
- if (FileInfo(cppSourcePath_).lastModified() >
- FileInfo(generatedCppSourcePath()).lastModified())
- return true;
-
- // no dynlib means we're dirty
- if (!FileInfo(dynlibPath()).exists())
- return true;
-
- // not dirty
- return false;
- }
-
- void regenerateSource() {
-
- // create new dynlib filename
- previousDynlibFilename_ = dynlibFilename_;
- dynlibFilename_ = "sourceCpp_" + createRandomizer() + dynlibExt_;
-
- // copy the source file to the build dir
- Rcpp::Function filecopy = Rcpp::Environment::base_env()["file.copy"];
- filecopy(cppSourcePath_, generatedCppSourcePath(), true);
-
- // parse attributes
- SourceFileAttributesParser sourceAttributes(cppSourcePath_);
-
- // generate cpp for attributes and append them
- std::ostringstream ostr;
- // always include Rcpp.h in case the user didn't
- ostr << std::endl << std::endl;
- ostr << "#include <Rcpp.h>" << std::endl;
- generateCpp(ostr, sourceAttributes, false, false, contextId_);
- generatedCpp_ = ostr.str();
- std::ofstream cppOfs(generatedCppSourcePath().c_str(),
- std::ofstream::out | std::ofstream::app);
- if (cppOfs.fail())
- throw Rcpp::file_io_error(generatedCppSourcePath());
- cppOfs << generatedCpp_;
- cppOfs.close();
-
- // generate R for attributes and write it into the build directory
- std::ofstream rOfs(generatedRSourcePath().c_str(),
- std::ofstream::out | std::ofstream::trunc);
- if (rOfs.fail())
- throw Rcpp::file_io_error(generatedRSourcePath());
-
- // DLLInfo - hide using . and ensure uniqueness using contextId
- std::string dllInfo = "`." + contextId_ + "_DLLInfo`";
- rOfs << dllInfo << " <- dyn.load('" << dynlibPath() << "')"
- << std::endl << std::endl;
-
- // Generate R functions
- generateR(rOfs, sourceAttributes, dllInfo);
-
- // remove the DLLInfo
- rOfs << std::endl << "rm(" << dllInfo << ")"
- << std::endl;
-
- rOfs.close();
-
- // discover exported functions, and dependencies
- exportedFunctions_.clear();
- depends_.clear();
- for (SourceFileAttributesParser::const_iterator
- it = sourceAttributes.begin(); it != sourceAttributes.end(); ++it) {
- if (it->name() == kExportAttribute && !it->function().empty())
- exportedFunctions_.push_back(it->exportedName());
-
- else if (it->name() == kDependsAttribute) {
- for (size_t i = 0; i<it->params().size(); ++i)
- depends_.push_back(it->params()[i].name());
- }
- }
-
- // capture embededded R
- embeddedR_ = sourceAttributes.embeddedR();
- }
-
- const std::string& contextId() const {
- return contextId_;
- }
-
- const std::string& cppSourcePath() const {
- return cppSourcePath_;
- }
-
- std::string buildDirectory() const {
- return buildDirectory_;
- }
-
- std::string generatedCpp() const {
- return generatedCpp_;
- }
-
- std::string cppSourceFilename() const {
- return cppSourceFilename_;
- }
-
- std::string rSourceFilename() const {
- return cppSourceFilename() + ".R";
- }
-
- std::string dynlibFilename() const {
- return dynlibFilename_;
- }
-
- std::string dynlibPath() const {
- return buildDirectory_ + fileSep_ + dynlibFilename();
- }
-
- std::string previousDynlibPath() const {
- if (!previousDynlibFilename_.empty())
- return buildDirectory_ + fileSep_ + previousDynlibFilename_;
- else
- return std::string();
- }
-
- const std::vector<std::string>& exportedFunctions() const {
- return exportedFunctions_;
- }
-
- const std::vector<std::string>& depends() const { return depends_; };
-
- const std::vector<std::string>& embeddedR() const { return embeddedR_; }
-
- private:
-
- std::string generatedCppSourcePath() const {
- return buildDirectory_ + fileSep_ + cppSourceFilename();
- }
-
- std::string generatedRSourcePath() const {
- return buildDirectory_ + fileSep_ + rSourceFilename();
- }
-
- void generateR(std::ostream& ostr,
- const SourceFileAttributes& attributes,
- const std::string& dllInfo) const
- {
- // process each attribute
- for(std::vector<Attribute>::const_iterator
- it = attributes.begin(); it != attributes.end(); ++it) {
-
- // alias the attribute and function (bail if not export)
- const Attribute& attribute = *it;
- if (!attribute.isExportedFunction())
- continue;
- const Function& function = attribute.function();
-
- // export the function
- ostr << attribute.exportedName()
- << " <- Rcpp:::sourceCppFunction("
- << "function(" << generateRArgList(function) << ") {}, "
- << dllInfo << ", "
- << "'" << contextId_ + "_" + function.name()
- << "')" << std::endl;
- }
-
- }
-
- std::string createRandomizer() {
- Rcpp::Function sample = Rcpp::Environment::base_env()["sample"];
- std::ostringstream ostr;
- ostr << Rcpp::as<int>(sample(100000, 1));
- return ostr.str();
- }
-
- private:
- std::string cppSourcePath_;
- std::string generatedCpp_;
- std::string cppSourceFilename_;
- std::string contextId_;
- std::string buildDirectory_;
- std::string fileSep_;
- std::string dynlibFilename_;
- std::string previousDynlibFilename_;
- std::string dynlibExt_;
- std::vector<std::string> exportedFunctions_;
- std::vector<std::string> depends_;
- std::vector<std::string> embeddedR_;
- };
-
- // Dynlib cache that allows lookup by either file path or code contents
- class SourceCppDynlibCache {
-
- public:
- SourceCppDynlibCache() {}
-
- private:
- // prohibit copying
- SourceCppDynlibCache(const SourceCppDynlibCache&);
- SourceCppDynlibCache& operator=(const SourceCppDynlibCache&);
-
- public:
- // Insert into cache by file name
- SourceCppDynlib* insertFile(const std::string& file,
- const SourceCppDynlib& dynlib) {
- Entry entry;
- entry.file = file;
- entry.dynlib = dynlib;
- entries_.push_back(entry);
- return &(entries_.rbegin()->dynlib);
- }
-
- // Insert into cache by code
- SourceCppDynlib* insertCode(const std::string& code,
- const SourceCppDynlib& dynlib) {
- Entry entry;
- entry.code = code;
- entry.dynlib = dynlib;
- entries_.push_back(entry);
- return &(entries_.rbegin()->dynlib);
- }
-
- // Lookup by file
- SourceCppDynlib* lookupByFile(const std::string& file) {
- for (std::size_t i = 0; i < entries_.size(); i++) {
- if (entries_[i].file == file)
- return &(entries_[i].dynlib);
- }
-
- return NULL;
- }
-
- // Lookup by code
- SourceCppDynlib* lookupByCode(const std::string& code) {
- for (std::size_t i = 0; i < entries_.size(); i++) {
- if (entries_[i].code == code)
- return &(entries_[i].dynlib);
- }
-
- return NULL;
- }
-
- private:
- struct Entry {
- std::string file;
- std::string code;
- SourceCppDynlib dynlib;
- };
- std::vector<Entry> entries_;
- };
-
-} // anonymous namespace
-
-// Create temporary build directory, generate code as necessary, and return
-// the context required for the sourceCpp function to complete it's work
-RcppExport SEXP sourceCppContext(SEXP sFile, SEXP sCode, SEXP sPlatform) {
-BEGIN_RCPP
- // parameters
- std::string file = Rcpp::as<std::string>(sFile);
- std::string code = sCode != R_NilValue ? Rcpp::as<std::string>(sCode) : "";
- Rcpp::List platform = Rcpp::as<Rcpp::List>(sPlatform);
-
- // get dynlib (using cache if possible)
- static SourceCppDynlibCache s_dynlibCache;
- SourceCppDynlib* pDynlib = !code.empty() ? s_dynlibCache.lookupByCode(code)
- : s_dynlibCache.lookupByFile(file);
-
- // check dynlib build state
- bool buildRequired = false;
-
- // if there is no dynlib in the cache then create one
- if (pDynlib == NULL) {
- buildRequired = true;
- SourceCppDynlib newDynlib(file, platform);
- if (!code.empty())
- pDynlib = s_dynlibCache.insertCode(code, newDynlib);
- else
- pDynlib = s_dynlibCache.insertFile(file, newDynlib);
- }
-
- // if the cached dynlib is dirty then regenerate the source
- else if (pDynlib->isSourceDirty()) {
- buildRequired = true;
- pDynlib->regenerateSource();
- }
-
- // if the dynlib hasn't yet been built then note that
- else if (!pDynlib->isBuilt()) {
- buildRequired = true;
- }
-
- // return context as a list
- using namespace Rcpp;
- return List::create(
- _["contextId"] = pDynlib->contextId(),
- _["cppSourcePath"] = pDynlib->cppSourcePath(),
- _["buildRequired"] = buildRequired,
- _["buildDirectory"] = pDynlib->buildDirectory(),
- _["generatedCpp"] = pDynlib->generatedCpp(),
- _["exportedFunctions"] = pDynlib->exportedFunctions(),
- _["cppSourceFilename"] = pDynlib->cppSourceFilename(),
- _["rSourceFilename"] = pDynlib->rSourceFilename(),
- _["dynlibFilename"] = pDynlib->dynlibFilename(),
- _["dynlibPath"] = pDynlib->dynlibPath(),
- _["previousDynlibPath"] = pDynlib->previousDynlibPath(),
- _["depends"] = pDynlib->depends(),
- _["embeddedR"] = pDynlib->embeddedR());
-END_RCPP
-}
-
-// Compile the attributes within the specified package directory into
-// RcppExports.cpp and RcppExports.R
-RcppExport SEXP compileAttributes(SEXP sPackageDir,
- SEXP sPackageName,
- SEXP sDepends,
- SEXP sCppFiles,
- SEXP sCppFileBasenames,
- SEXP sIncludes,
- SEXP sVerbose,
- SEXP sPlatform) {
-BEGIN_RCPP
- // arguments
- std::string packageDir = Rcpp::as<std::string>(sPackageDir);
- std::string packageName = Rcpp::as<std::string>(sPackageName);
-
- Rcpp::CharacterVector vDepends = Rcpp::as<Rcpp::CharacterVector>(sDepends);
- std::set<std::string> depends;
- for (Rcpp::CharacterVector::iterator
- it = vDepends.begin(); it != vDepends.end(); ++it) {
- depends.insert(std::string(*it));
- }
-
- std::vector<std::string> cppFiles =
- Rcpp::as<std::vector<std::string> >(sCppFiles);
- std::vector<std::string> cppFileBasenames =
- Rcpp::as<std::vector<std::string> >(sCppFileBasenames);
- std::vector<std::string> includes =
- 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"]);
-
- // initialize generators
- ExportsGenerators generators;
- generators.add(new CppExportsGenerator(packageDir, packageName, fileSep));
- generators.add(new RExportsGenerator(packageDir, packageName, fileSep));
-
- // catch file exists exception if the include file already exists
- // and we are unable to overwrite it
- try {
- generators.add(new CppExportsIncludeGenerator(packageDir,
- packageName,
- fileSep));
- }
- catch(const Rcpp::file_exists& e) {
- std::string msg =
- "The header file '" + e.filePath() + "' already exists so "
- "cannot be overwritten by Rcpp::interfaces";
- throw Rcpp::exception(msg.c_str(), __FILE__, __LINE__);
- }
-
- // catch file exists exception for package include (because if it
- // already exists we simply leave it alone)
- try {
- generators.add(new CppPackageIncludeGenerator(packageDir,
- packageName,
- fileSep));
- }
- catch(const Rcpp::file_exists& e) {}
-
- // write begin
- generators.writeBegin();
-
- // Parse attributes from each file and generate code as required.
- bool haveAttributes = false;
- std::set<std::string> dependsAttribs;
- for (std::size_t i=0; i<cppFiles.size(); i++) {
-
- // parse attributes (continue if there are none)
- std::string cppFile = cppFiles[i];
- SourceFileAttributesParser attributes(cppFile);
- if (attributes.empty())
- continue;
-
- // confirm we have attributes
- haveAttributes = true;
-
- // write functions
- generators.writeFunctions(attributes, verbose);
-
- // track depends
- for (SourceFileAttributesParser::const_iterator
- it = attributes.begin(); it != attributes.end(); ++it) {
- if (it->name() == kDependsAttribute) {
- for (size_t i = 0; i<it->params().size(); ++i)
- dependsAttribs.insert(it->params()[i].name());
- }
- }
- }
-
- // write end
- generators.writeEnd();
-
- // commit or remove
- std::vector<std::string> updated;
- if (haveAttributes)
- updated = generators.commit(includes);
- else
- updated = generators.remove();
-
- // print warning if there are depends attributes that don't have
- // corresponding entries in the DESCRIPTION file
- std::vector<std::string> diff;
- std::set_difference(dependsAttribs.begin(), dependsAttribs.end(),
- depends.begin(), depends.end(),
- std::back_inserter(diff));
- if (!diff.empty()) {
- std::string msg =
- "The following packages are referenced using Rcpp::depends "
- "attributes however are not listed in the Depends and LinkingTo "
- "fields of the package DESCRIPTION file: ";
- for (size_t i=0; i<diff.size(); i++) {
- msg += diff[i];
- if (i != (diff.size()-1))
- msg += ", ";
- }
- showWarning(msg);
- }
-
- // verbose output
- if (verbose) {
- for (size_t i=0; i<updated.size(); i++)
- Rcpp::Rcout << updated[i] << " updated." << std::endl;
- }
-
- // return files updated
- return Rcpp::wrap<std::vector<std::string> >(updated);
-END_RCPP
-}
-
Deleted: pkg/Rcpp/src/AttributesGen.cpp
===================================================================
--- pkg/Rcpp/src/AttributesGen.cpp 2012-12-11 15:21:06 UTC (rev 4149)
+++ pkg/Rcpp/src/AttributesGen.cpp 2012-12-11 15:27:18 UTC (rev 4150)
@@ -1,874 +0,0 @@
-// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
-//
-// AttributesGen.cpp: Rcpp R/C++ interface class library -- Rcpp attributes
-//
-// Copyright (C) 2012 JJ Allaire, Dirk Eddelbuettel and Romain Francois
-//
-// This file is part of Rcpp.
-//
-// Rcpp is free software: you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 2 of the License, or
-// (at your option) any later version.
-//
-// Rcpp is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
-
-#include "AttributesGen.h"
-#include "AttributesUtil.h"
-#include "AttributesTypes.h"
-
-#include <fstream>
-
-#include <Rcpp/iostream/Rostream.h>
-#include <Rcpp/exceptions.h>
-
-namespace Rcpp {
-namespace attributes {
-
- // constants
- namespace {
- const char * const kRcppExportsSuffix = "_RcppExports.h";
- const char * const kTrySuffix = "_try";
- }
-
- ExportsGenerator::ExportsGenerator(const std::string& targetFile,
- const std::string& package,
- const std::string& commentPrefix)
- : targetFile_(targetFile),
- package_(package),
- commentPrefix_(commentPrefix),
- hasCppInterface_(false) {
-
- // read the existing target file if it exists
- if (FileInfo(targetFile_).exists()) {
- std::ifstream ifs(targetFile_.c_str());
- if (ifs.fail())
- throw Rcpp::file_io_error(targetFile_);
- std::stringstream buffer;
- buffer << ifs.rdbuf();
- existingCode_ = buffer.str();
- }
-
- // see if this is safe to overwite and throw if it isn't
- if (!isSafeToOverwrite())
- throw Rcpp::file_exists(targetFile_);
- }
-
- void ExportsGenerator::writeFunctions(
- const SourceFileAttributes& attributes,
- bool verbose) {
-
- if (attributes.hasInterface(kInterfaceCpp))
- hasCppInterface_ = true;
-
- doWriteFunctions(attributes, verbose);
- }
-
- // 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)
- bool ExportsGenerator::commit(const std::string& preamble) {
-
- // get the generated code
- std::string code = codeStream_.str();
-
- // if there is no generated code AND the exports file does not
- // currently exist then do nothing
- if (code.empty() && !FileInfo(targetFile_).exists())
- return false;
-
- // write header/preamble
- std::ostringstream headerStream;
- headerStream << commentPrefix_ << " This file was generated by "
- << "Rcpp::compileAttributes" << std::endl;
- headerStream << commentPrefix_ << " Generator token: "
- << generatorToken() << std::endl << std::endl;
- if (!preamble.empty())
- headerStream << preamble;
-
- // get generated code and only write it if there was a change
- std::string generatedCode = headerStream.str() + code;
- if (generatedCode != existingCode_) {
- // open the file
- std::ofstream ofs(targetFile_.c_str(),
- std::ofstream::out | std::ofstream::trunc);
- if (ofs.fail())
- throw Rcpp::file_io_error(targetFile_);
-
- // write generated code and return
- ofs << generatedCode;
- ofs.close();
- return true;
- }
- else {
- return false;
- }
- }
-
- // Remove the generated file entirely
- bool ExportsGenerator::remove() {
- return removeFile(targetFile_);
- }
-
- CppExportsGenerator::CppExportsGenerator(const std::string& packageDir,
- const std::string& package,
- const std::string& fileSep)
- : ExportsGenerator(
- packageDir + fileSep + "src" + fileSep + "RcppExports.cpp",
- package,
- "//")
- {
- }
-
- void CppExportsGenerator::doWriteFunctions(
- const SourceFileAttributes& attributes,
- bool verbose) {
-
- // generate functions
- generateCpp(ostr(),
- attributes,
- true,
- attributes.hasInterface(kInterfaceCpp),
- package());
-
- // track cppExports and signatures (we use these at the end to
- // generate the ValidateSignature and RegisterCCallable functions)
- if (attributes.hasInterface(kInterfaceCpp)) {
- for (SourceFileAttributes::const_iterator
- it = attributes.begin(); it != attributes.end(); ++it) {
- if (it->isExportedFunction()) {
- // add it to the list if it's not hidden
- Function fun = it->function().renamedTo(it->exportedName());
- if (!fun.isHidden())
- cppExports_.push_back(*it);
- }
- }
- }
-
- // verbose if requested
- if (verbose) {
- Rcpp::Rcout << "Exports from " << attributes.sourceFile() << ":"
- << std::endl;
- for (std::vector<Attribute>::const_iterator
- it = attributes.begin(); it != attributes.end(); ++it) {
- if (it->isExportedFunction())
- Rcpp::Rcout << " " << it->function() << std::endl;
- }
- Rcpp::Rcout << std::endl;
- }
- }
-
- void CppExportsGenerator::writeEnd()
- {
- // generate a function that can be used to validate exported
- // functions and their signatures prior to looking up with
- // GetCppCallable (otherwise inconsistent signatures between
- // client and library would cause a crash)
- if (hasCppInterface()) {
-
- ostr() << std::endl;
- ostr() << "// validate"
- << " (ensure exported C++ functions exist before "
- << "calling them)" << std::endl;
- ostr() << "static int " << exportValidationFunctionRegisteredName()
- << "(const char* sig) { " << std::endl;
- ostr() << " static std::set<std::string> signatures;"
- << std::endl;
- ostr() << " if (signatures.empty()) {" << std::endl;
-
- for (std::size_t i=0;i<cppExports_.size(); i++) {
- const Attribute& attr = cppExports_[i];
- ostr() << " signatures.insert(\""
- << attr.function().signature(attr.exportedName())
- << "\");" << std::endl;
- }
- ostr() << " }" << std::endl;
- ostr() << " return signatures.find(sig) != signatures.end();"
- << std::endl;
- ostr() << "}" << std::endl;
-
- // generate a function that will register all of our C++
- // exports as C-callable from other packages
- ostr() << std::endl;
- ostr() << "// registerCCallable (register entry points for "
- "exported C++ functions)" << std::endl;
- ostr() << "RcppExport SEXP " << registerCCallableExportedName()
- << "() { " << std::endl;
- for (std::size_t i=0;i<cppExports_.size(); i++) {
- const Attribute& attr = cppExports_[i];
- std::string name = package() + "_" + attr.exportedName();
- ostr() << registerCCallable(
- 4,
- attr.exportedName(),
- attr.function().name() + kTrySuffix);
- ostr() << std::endl;
- }
- ostr() << registerCCallable(4,
- exportValidationFunction(),
- exportValidationFunction());
- ostr() << std::endl;
- ostr() << " return R_NilValue;" << std::endl;
- ostr() << "}" << std::endl;
- }
- }
-
- std::string CppExportsGenerator::registerCCallable(
- size_t indent,
- const std::string& exportedName,
[TRUNCATED]
To get the complete diff run:
svnlook diff /svnroot/rcpp -r 4150
More information about the Rcpp-commits
mailing list