1 // 2 // Module.h: Rcpp R/C++ interface class library -- Rcpp modules 3 // 4 // Copyright (C) 2012 - 2020 Dirk Eddelbuettel and Romain Francois 5 // 6 // This file is part of Rcpp. 7 // 8 // Rcpp is free software: you can redistribute it and/or modify it 9 // under the terms of the GNU General Public License as published by 10 // the Free Software Foundation, either version 2 of the License, or 11 // (at your option) any later version. 12 // 13 // Rcpp is distributed in the hope that it will be useful, but 14 // WITHOUT ANY WARRANTY; without even the implied warranty of 15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 // GNU General Public License for more details. 17 // 18 // You should have received a copy of the GNU General Public License 19 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>. 20 21 #ifndef Rcpp_Module_Module_h 22 #define Rcpp_Module_Module_h 23 24 namespace Rcpp { 25 26 /** 27 * holds information about exposed functions and classes 28 */ 29 class Module { 30 public: 31 typedef std::map<std::string,CppFunction*> MAP ; 32 typedef std::pair<const std::string,CppFunction*> FUNCTION_PAIR ; 33 34 typedef std::map<std::string,class_Base*> CLASS_MAP ; 35 typedef std::pair<const std::string,class_Base*> CLASS_PAIR ; 36 typedef CLASS_MAP::iterator CLASS_ITERATOR ; 37 Module()38 Module() : 39 name(), functions(), classes(), prefix() {} 40 Module(const char * name_)41 Module(const char* name_) : 42 name(name_), functions(), classes(), prefix("Rcpp_module_"){ 43 prefix += name ; 44 } 45 46 /** 47 * calls a function from that module with the specified arguments 48 * 49 * @param name the name of the function to call 50 * @param args an array of R objects to use as arguments for the function 51 * @param nargs number of arguments 52 */ invoke(const std::string & name_,SEXP * args,int nargs)53 inline SEXP invoke( const std::string& name_, SEXP* args, int nargs){ // #nocov start 54 MAP::iterator it = functions.find( name_ ); 55 if( it == functions.end() ){ 56 throw std::range_error( "no such function" ) ; 57 } 58 CppFunction* fun = it->second ; 59 if( fun->nargs() > nargs ){ 60 throw std::range_error( "incorrect number of arguments" ) ; 61 } 62 63 return List::create( 64 _["result"] = fun->operator()( args ), 65 _["void"] = fun->is_void() 66 ) ; 67 } 68 69 /** 70 * vector of arity of all the functions exported by the module 71 */ functions_arity()72 IntegerVector functions_arity(){ 73 size_t n = functions.size() ; 74 IntegerVector x( n ) ; 75 CharacterVector names( n ); 76 MAP::iterator it = functions.begin() ; 77 for( size_t i=0; i<n; i++, ++it){ 78 x[i] = (it->second)->nargs() ; 79 names[i] = it->first ; 80 } 81 x.names() = names ; 82 return x ; 83 } // #nocov end 84 85 /** 86 * vector of names of the functions 87 */ functions_names()88 CharacterVector functions_names(){ 89 size_t n = functions.size() ; 90 CharacterVector names( n ); 91 MAP::iterator it = functions.begin() ; 92 for( size_t i=0; i<n; i++, ++it){ 93 names[i] = it->first ; 94 } 95 return names ; 96 } 97 98 /** 99 * exposed class names 100 */ class_names()101 inline CharacterVector class_names(){ 102 size_t n = classes.size() ; 103 CharacterVector names( n ); 104 CLASS_MAP::iterator it = classes.begin() ; 105 for( size_t i=0; i<n; i++, ++it){ 106 names[i] = it->first ; 107 } 108 return names ; 109 } 110 111 /** 112 * information about the classes 113 */ 114 List classes_info() ; 115 116 /** 117 * completion information 118 */ complete()119 CharacterVector complete(){ // #nocov start 120 size_t nf = functions.size() ; 121 size_t nc = classes.size() ; 122 size_t n = nf + nc ; 123 CharacterVector res( n ) ; 124 size_t i=0; 125 MAP::iterator it = functions.begin(); 126 std::string buffer ; 127 for( ; i<nf; i++, ++it) { 128 buffer = it->first ; 129 if( (it->second)->nargs() == 0 ) { 130 buffer += "() " ; 131 } else { 132 buffer += "( " ; 133 } 134 res[i] = buffer ; 135 } 136 CLASS_MAP::iterator cit = classes.begin() ; 137 for( size_t j=0; j<nc; j++, i++, ++cit){ 138 res[i] = cit->first ; 139 } 140 return res ; 141 } // #nocov end 142 143 /** 144 * Returns a list that contains: 145 * - an external pointer that encapsulates a CppFunction* 146 * - voidness of the function (logical) 147 * - docstring (character) 148 * - signature (character) 149 * - formal arguments of the function 150 * 151 * The R code in Module.R uses this information to create a C++Function 152 * object 153 */ get_function(const std::string & name_)154 inline SEXP get_function( const std::string& name_ ){ 155 MAP::iterator it = functions.begin() ; 156 size_t n = functions.size() ; 157 CppFunction* fun = 0 ; 158 for( size_t i=0; i<n; i++, ++it){ 159 if( name_.compare( it->first ) == 0){ 160 fun = it->second ; 161 break ; 162 } 163 } 164 std::string sign ; 165 fun->signature( sign, name_.data() ) ; 166 return List::create( 167 XPtr<CppFunction>( fun, false ), 168 fun->is_void(), 169 fun->docstring, 170 sign, 171 fun->get_formals(), 172 fun->nargs() 173 ) ; 174 } 175 176 /** 177 * get the underlying C++ function pointer as a DL_FUNC 178 */ get_function_ptr(const std::string & name_)179 inline DL_FUNC get_function_ptr( const std::string& name_ ){ 180 MAP::iterator it = functions.begin() ; 181 size_t n = functions.size() ; 182 CppFunction* fun = 0 ; 183 for( size_t i=0; i<n; i++, ++it){ 184 if( name_.compare( it->first ) == 0){ 185 fun = it->second ; 186 break ; 187 } 188 } 189 return fun->get_function_ptr() ; 190 } 191 Add(const char * name_,CppFunction * ptr)192 inline void Add( const char* name_ , CppFunction* ptr){ 193 R_RegisterCCallable( prefix.c_str(), name_, ptr->get_function_ptr() ) ; 194 functions.insert( FUNCTION_PAIR( name_ , ptr ) ) ; 195 } 196 AddClass(const char * name_,class_Base * cptr)197 inline void AddClass(const char* name_ , class_Base* cptr){ 198 classes.insert( CLASS_PAIR( name_ , cptr ) ) ; 199 } 200 has_function(const std::string & m)201 inline bool has_function( const std::string& m){ // #nocov start 202 return functions.find(m) != functions.end() ; 203 } 204 has_class(const std::string & m)205 inline bool has_class( const std::string& m){ 206 return classes.find(m) != classes.end() ; 207 } // #nocov end 208 209 CppClass get_class( const std::string& cl ) ; 210 get_class_pointer(const std::string & cl)211 class_Base* get_class_pointer(const std::string& cl){ 212 CLASS_MAP::iterator it = classes.find(cl) ; 213 if( it == classes.end() ) throw std::range_error( "no such class" ) ; 214 return it->second ; 215 } 216 217 std::string name ; 218 add_enum(const std::string & parent_class_typeinfo_name,const std::string & enum_name,const std::map<std::string,int> & value)219 void add_enum( const std::string& parent_class_typeinfo_name, const std::string& enum_name, const std::map<std::string, int>& value ){ 220 // find the parent class 221 CLASS_ITERATOR it ; 222 class_Base* target_class = NULL; 223 for( it = classes.begin(); it != classes.end(); it++){ 224 if( it->second->has_typeinfo_name(parent_class_typeinfo_name) ){ 225 target_class = it->second ; 226 } 227 } 228 229 // TODO: add the enum to the class 230 target_class->add_enum( enum_name, value ) ; 231 } 232 233 private: 234 MAP functions ; 235 CLASS_MAP classes ; 236 std::string prefix ; 237 238 }; 239 240 } 241 242 #endif 243