[Rcpp-commits] r4109 - in pkg/Rcpp: . R inst/include/Rcpp src
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Thu Dec 6 21:15:48 CET 2012
Author: jjallaire
Date: 2012-12-06 21:15:48 +0100 (Thu, 06 Dec 2012)
New Revision: 4109
Modified:
pkg/Rcpp/ChangeLog
pkg/Rcpp/DESCRIPTION
pkg/Rcpp/R/Attributes.R
pkg/Rcpp/inst/include/Rcpp/exceptions.h
pkg/Rcpp/inst/include/Rcpp/preprocessor.h
pkg/Rcpp/src/Attributes.cpp
pkg/Rcpp/src/AttributesGen.cpp
pkg/Rcpp/src/AttributesGen.h
pkg/Rcpp/src/RcppCommon.cpp
Log:
convert 'try-error'to exception for C++ interfaces; don't re-use shared lib in sourceCpp
Modified: pkg/Rcpp/ChangeLog
===================================================================
--- pkg/Rcpp/ChangeLog 2012-12-06 13:55:31 UTC (rev 4108)
+++ pkg/Rcpp/ChangeLog 2012-12-06 20:15:48 UTC (rev 4109)
@@ -1,10 +1,19 @@
2012-12-06 JJ Allaire <jj at rstudio.org>
- * R/Attributes.R: revert DOS newlines
- * src/Attributes.cpp: revert DOS newlines; define RCPP_NO_SUGAR
- * src/AttributesGen.cpp: revert DOS newlines
+ * R/Attributes.R: revert DOS newlines; use new shared library name
+ for each rebuild in sourceCpp
+ * src/Attributes.cpp: revert DOS newlines; define RCPP_NO_SUGAR;
+ use new shared library name for each rebuild in sourceCpp
+ * src/AttributesGen.cpp: revert DOS newlines; convert 'try-error'
+ to exception for C++ interfaces
+ * src/AttributesGen.h: 'try-error' to exception for C++ interfaces
* src/AttributesParser.cpp: revert DOS newlines; define RCPP_NO_SUGAR
+ * src/RcppCommon.cpp: conversion from exeption to 'try-error'
+ * include/Rcpp/exceptions.h: conversion from exeption to 'try-error'
+ * include/Rcpp/preprocessor.h: add END_RCPP_RETURN_ERROR macro
+ to convert exceptions to 'try-error' objects
* include/Rcpp/iostream/Rstreambuf.h: revert DOS newlines
+ * DESCRIPTION: bump version to 0.10.1.5
2012-12-06 Dirk Eddelbuettel <edd at debian.org>
Modified: pkg/Rcpp/DESCRIPTION
===================================================================
--- pkg/Rcpp/DESCRIPTION 2012-12-06 13:55:31 UTC (rev 4108)
+++ pkg/Rcpp/DESCRIPTION 2012-12-06 20:15:48 UTC (rev 4109)
@@ -1,6 +1,6 @@
Package: Rcpp
Title: Seamless R and C++ Integration
-Version: 0.10.1.4
+Version: 0.10.1.5
Date: $Date$
Author: Dirk Eddelbuettel and Romain Francois, with contributions
by Douglas Bates, John Chambers and JJ Allaire
Modified: pkg/Rcpp/R/Attributes.R
===================================================================
--- pkg/Rcpp/R/Attributes.R 2012-12-06 13:55:31 UTC (rev 4108)
+++ pkg/Rcpp/R/Attributes.R 2012-12-06 20:15:48 UTC (rev 4109)
@@ -82,9 +82,9 @@
})
# unload and delete existing dylib if necessary
- if (file.exists(context$dynlibPath)) {
- try(silent=T, dyn.unload(context$dynlibPath))
- file.remove(context$dynlibPath)
+ if (file.exists(context$previousDynlibPath)) {
+ try(silent=T, dyn.unload(context$previousDynlibPath))
+ file.remove(context$previousDynlibPath)
}
# prepare the command (output if we are in showOutput mode)
Modified: pkg/Rcpp/inst/include/Rcpp/exceptions.h
===================================================================
--- pkg/Rcpp/inst/include/Rcpp/exceptions.h 2012-12-06 13:55:31 UTC (rev 4108)
+++ pkg/Rcpp/inst/include/Rcpp/exceptions.h 2012-12-06 20:15:48 UTC (rev 4109)
@@ -129,6 +129,8 @@
void forward_uncaught_exceptions_to_r() ;
void forward_exception_to_r( const std::exception& ) ;
+SEXP exception_to_try_error( const std::exception& ) ;
+SEXP string_to_try_error( const std::string& ) ;
std::string demangle( const std::string& name) ;
#define DEMANGLE(__TYPE__) demangle( typeid(__TYPE__).name() ).c_str()
Modified: pkg/Rcpp/inst/include/Rcpp/preprocessor.h
===================================================================
--- pkg/Rcpp/inst/include/Rcpp/preprocessor.h 2012-12-06 13:55:31 UTC (rev 4108)
+++ pkg/Rcpp/inst/include/Rcpp/preprocessor.h 2012-12-06 20:15:48 UTC (rev 4109)
@@ -59,6 +59,10 @@
#define END_RCPP VOID_END_RCPP return R_NilValue;
#endif
+#ifndef END_RCPP_RETURN_ERROR
+#define END_RCPP_RETURN_ERROR } catch( std::exception& __ex__ ){ return exception_to_try_error( __ex__ ) ; } catch(...){ return string_to_try_error( "c++ exception (unknown reason)" ) ; } return R_NilValue;
+#endif
+
#include <Rcpp/preprocessor_generated.h>
// from boost preprocessor library
#include <Rcpp/preprocessor/cat.hpp>
Modified: pkg/Rcpp/src/Attributes.cpp
===================================================================
--- pkg/Rcpp/src/Attributes.cpp 2012-12-06 13:55:31 UTC (rev 4108)
+++ pkg/Rcpp/src/Attributes.cpp 2012-12-06 20:15:48 UTC (rev 4109)
@@ -168,10 +168,7 @@
dircreate(buildDirectory_);
// generate a random context id
- Rcpp::Function sample = Rcpp::Environment::base_env()["sample"];
- std::ostringstream ostr;
- ostr << "sourceCpp_" << Rcpp::as<int>(sample(100000, 1));
- contextId_ = ostr.str();
+ contextId_ = "sourceCpp_" + createRandomizer();
// regenerate the source code
regenerateSource();
@@ -197,6 +194,10 @@
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);
@@ -209,7 +210,7 @@
// 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, contextId_);
+ generateCpp(ostr, sourceAttributes, false, false, contextId_);
generatedCpp_ = ostr.str();
std::ofstream cppOfs(generatedCppSourcePath().c_str(),
std::ofstream::out | std::ofstream::app);
@@ -281,12 +282,19 @@
}
std::string dynlibFilename() const {
- return contextId() + dynlibExt_;
+ 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_;
@@ -331,6 +339,13 @@
}
+ 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_;
@@ -338,6 +353,8 @@
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_;
@@ -458,6 +475,7 @@
_["rSourceFilename"] = pDynlib->rSourceFilename(),
_["dynlibFilename"] = pDynlib->dynlibFilename(),
_["dynlibPath"] = pDynlib->dynlibPath(),
+ _["previousDynlibPath"] = pDynlib->previousDynlibPath(),
_["depends"] = pDynlib->depends(),
_["embeddedR"] = pDynlib->embeddedR());
END_RCPP
Modified: pkg/Rcpp/src/AttributesGen.cpp
===================================================================
--- pkg/Rcpp/src/AttributesGen.cpp 2012-12-06 13:55:31 UTC (rev 4108)
+++ pkg/Rcpp/src/AttributesGen.cpp 2012-12-06 20:15:48 UTC (rev 4109)
@@ -34,6 +34,7 @@
// constants
namespace {
const char * const kRcppExportsSuffix = "_RcppExports.h";
+ const char * const kTrySuffix = "_try";
}
ExportsGenerator::ExportsGenerator(const std::string& targetFile,
@@ -130,7 +131,11 @@
bool verbose) {
// generate functions
- generateCpp(ostr(), attributes, true, package());
+ 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)
@@ -198,9 +203,10 @@
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());
+ ostr() << registerCCallable(
+ 4,
+ attr.exportedName(),
+ attr.function().name() + kTrySuffix);
ostr() << std::endl;
}
ostr() << registerCCallable(4,
@@ -352,9 +358,8 @@
<< std::endl;
ostr() << " }" << std::endl;
- ostr() << " SEXP resultSEXP = " << ptrName << "(";
+ ostr() << " RObject result = " << ptrName << "(";
-
const std::vector<Argument>& args = function.arguments();
for (std::size_t i = 0; i<args.size(); i++) {
ostr() << "Rcpp::wrap(" << args[i].name() << ")";
@@ -364,8 +369,13 @@
ostr() << ");" << std::endl;
+ ostr() << " if (result.inherits(\"try-error\"))"
+ << std::endl
+ << " throw Rcpp::exception(as<std::string>("
+ << "result).c_str());"
+ << std::endl;
ostr() << " return Rcpp::as<" << function.type() << " >"
- << "(resultSEXP);" << std::endl;
+ << "(result);" << std::endl;
ostr() << " }" << std::endl << std::endl;
}
@@ -762,6 +772,7 @@
void generateCpp(std::ostream& ostr,
const SourceFileAttributes& attributes,
bool includePrototype,
+ bool cppInterface,
const std::string& contextId) {
// process each attribute
@@ -780,19 +791,26 @@
ostr << function << ";";
}
- // write the SEXP-based function
- ostr << std::endl << "RcppExport SEXP ";
- if (!contextId.empty())
- ostr << contextId << "_";
- ostr << function.name() << "(";
+ // write the C++ callable SEXP-based function (this version
+ // returns errors via "try-error")
+ ostr << std::endl;
+ ostr << (cppInterface ? "static" : "RcppExport");
+ ostr << " SEXP ";
+ std::string funcName = contextId + "_" + function.name();
+ ostr << funcName;
+ if (cppInterface)
+ ostr << kTrySuffix;
+ ostr << "(";
+ std::ostringstream ostrArgs;
const std::vector<Argument>& arguments = function.arguments();
for (size_t i = 0; i<arguments.size(); i++) {
const Argument& argument = arguments[i];
- ostr << "SEXP " << argument.name() << "SEXP";
+ ostrArgs << "SEXP " << argument.name() << "SEXP";
if (i != (arguments.size()-1))
- ostr << ", ";
+ ostrArgs << ", ";
}
- ostr << ") {" << std::endl;
+ std::string args = ostrArgs.str();
+ ostr << args << ") {" << std::endl;
ostr << "BEGIN_RCPP" << std::endl;
for (size_t i = 0; i<arguments.size(); i++) {
const Argument& argument = arguments[i];
@@ -818,8 +836,32 @@
std::string res = function.type().isVoid() ? "R_NilValue" :
"Rcpp::wrap(result)";
ostr << " return " << res << ";" << std::endl;
- ostr << "END_RCPP" << std::endl;
+ ostr << (cppInterface ? "END_RCPP_RETURN_ERROR" : "END_RCPP")
+ << std::endl;
ostr << "}" << std::endl;
+
+ // Now write an R wrapper that returns error via Rf_error
+ if (cppInterface) {
+ ostr << "RcppExport SEXP " << funcName << "(" << args << ") {"
+ << std::endl;
+ ostr << " SEXP result = PROTECT(" << funcName
+ << kTrySuffix << "(";
+ for (size_t i = 0; i<arguments.size(); i++) {
+ const Argument& argument = arguments[i];
+ ostr << argument.name() << "SEXP";
+ if (i != (arguments.size()-1))
+ ostr << ", ";
+ }
+ ostr << "));" << std::endl;
+ ostr << " "
+ << "Rboolean isError = Rf_inherits(result, \"try-error\");"
+ << std::endl;
+ ostr << " UNPROTECT(1);" << std::endl
+ << " if (isError)" << std::endl
+ << " Rf_error(CHAR(Rf_asChar(result)));" << std::endl
+ << " return result;" << std::endl
+ << "}" << std::endl;
+ }
}
}
Modified: pkg/Rcpp/src/AttributesGen.h
===================================================================
--- pkg/Rcpp/src/AttributesGen.h 2012-12-06 13:55:31 UTC (rev 4108)
+++ pkg/Rcpp/src/AttributesGen.h 2012-12-06 20:15:48 UTC (rev 4109)
@@ -239,10 +239,11 @@
// Standalone generation helpers (used by sourceCpp)
std::string generateRArgList(const Function& function);
-
+
void generateCpp(std::ostream& ostr,
const SourceFileAttributes& attributes,
bool includePrototype,
+ bool cppInterface,
const std::string& contextId);
} // namespace attributes
Modified: pkg/Rcpp/src/RcppCommon.cpp
===================================================================
--- pkg/Rcpp/src/RcppCommon.cpp 2012-12-06 13:55:31 UTC (rev 4108)
+++ pkg/Rcpp/src/RcppCommon.cpp 2012-12-06 20:15:48 UTC (rev 4109)
@@ -168,3 +168,26 @@
return Rcpp::wrap( (const char*)buffer ) ;
}
+SEXP exception_to_try_error( const std::exception& ex ){
+ return string_to_try_error(ex.what());
+}
+
+SEXP string_to_try_error( const std::string& str){
+
+ using namespace Rcpp;
+
+ // form simple error condition based on a string
+ SEXP rcppNS = PROTECT(R_FindNamespace(Rf_mkString("Rcpp")));
+ SEXP simpleErrorExpr = PROTECT(::Rcpp_lcons(::Rf_install("simpleError"),
+ pairlist(str, R_NilValue)));
+ SEXP simpleError = PROTECT(Rf_eval(simpleErrorExpr, rcppNS));
+
+ // create the try-error structure
+ SEXP structureExpr = PROTECT(::Rcpp_lcons(::Rf_install("structure"),
+ pairlist(str, _["class"] = "try-error", _["condition"] = simpleError)));
+ SEXP tryError = PROTECT(Rf_eval(structureExpr, rcppNS));
+
+ // unprotect and return
+ UNPROTECT(5);
+ return tryError;
+}
More information about the Rcpp-commits
mailing list