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