[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