1 //----------------------------------------------------------------------------- 2 // 3 // Copyright (c) 1998 - 2007, The Regents of the University of California 4 // Produced at the Lawrence Livermore National Laboratory 5 // All rights reserved. 6 // 7 // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The 8 // full copyright notice is contained in the file COPYRIGHT located at the root 9 // of the PyCXX distribution. 10 // 11 // Redistribution and use in source and binary forms, with or without 12 // modification, are permitted provided that the following conditions are met: 13 // 14 // - Redistributions of source code must retain the above copyright notice, 15 // this list of conditions and the disclaimer below. 16 // - Redistributions in binary form must reproduce the above copyright notice, 17 // this list of conditions and the disclaimer (as noted below) in the 18 // documentation and/or materials provided with the distribution. 19 // - Neither the name of the UC/LLNL nor the names of its contributors may be 20 // used to endorse or promote products derived from this software without 21 // specific prior written permission. 22 // 23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF 27 // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR 28 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 34 // DAMAGE. 35 // 36 //----------------------------------------------------------------------------- 37 38 #ifndef __CXX_ExtensionModule__h 39 #define __CXX_ExtensionModule__h 40 41 namespace Py 42 { 43 class ExtensionModuleBase 44 { 45 public: 46 ExtensionModuleBase( const char *name ); 47 virtual ~ExtensionModuleBase(); 48 49 Module module( void ) const; // only valid after initialize() has been called 50 Dict moduleDictionary( void ) const; // only valid after initialize() has been called 51 52 virtual Object invoke_method_noargs( void *method_def ) = 0; 53 virtual Object invoke_method_keyword( void *method_def, const Tuple &_args, const Dict &_keywords ) = 0; 54 virtual Object invoke_method_varargs( void *method_def, const Tuple &_args ) = 0; 55 56 const std::string &name() const; 57 const std::string &fullName() const; 58 59 // what is returned from PyInit_<module> function 60 Object moduleObject( void ) const; 61 62 protected: 63 // Initialize the module 64 void initialize( const char *module_doc ); 65 66 const std::string m_module_name; 67 const std::string m_full_module_name; 68 MethodTable m_method_table; 69 PyObject *m_module; 70 71 private: 72 // 73 // prevent the compiler generating these unwanted functions 74 // 75 ExtensionModuleBase( const ExtensionModuleBase & ); //unimplemented 76 void operator=( const ExtensionModuleBase & ); //unimplemented 77 }; 78 79 // Note: Python calls noargs as varargs buts args==NULL 80 extern "C" PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ); 81 extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ); 82 extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ); 83 84 extern "C" void do_not_dealloc( void * ); 85 86 template<TEMPLATE_TYPENAME T> 87 class ExtensionModule : public ExtensionModuleBase 88 { 89 public: ExtensionModule(const char * name)90 ExtensionModule( const char *name ) 91 : ExtensionModuleBase( name ) 92 {} ~ExtensionModule()93 virtual ~ExtensionModule() 94 {} 95 96 protected: 97 typedef Object (T::*method_noargs_function_t)(); 98 typedef Object (T::*method_varargs_function_t)( const Tuple &args ); 99 typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); 100 typedef std::map<std::string, MethodDefExt<T> *> method_map_t; 101 add_noargs_method(const char * name,method_noargs_function_t function,const char * doc="")102 static void add_noargs_method( const char *name, method_noargs_function_t function, const char *doc="" ) 103 { 104 method_map_t &mm = methods(); 105 mm[ std::string( name ) ] = new MethodDefExt<T>( name, function, method_noargs_call_handler, doc ); 106 } 107 add_varargs_method(const char * name,method_varargs_function_t function,const char * doc="")108 static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) 109 { 110 method_map_t &mm = methods(); 111 mm[ std::string( name ) ] = new MethodDefExt<T>( name, function, method_varargs_call_handler, doc ); 112 } 113 add_keyword_method(const char * name,method_keyword_function_t function,const char * doc="")114 static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) 115 { 116 method_map_t &mm = methods(); 117 mm[ std::string( name ) ] = new MethodDefExt<T>( name, function, method_keyword_call_handler, doc ); 118 } 119 initialize(const char * module_doc="")120 void initialize( const char *module_doc="" ) 121 { 122 ExtensionModuleBase::initialize( module_doc ); 123 Dict dict( moduleDictionary() ); 124 125 // 126 // put each of the methods into the modules dictionary 127 // so that we get called back at the function in T. 128 // 129 method_map_t &mm = methods(); 130 EXPLICIT_TYPENAME method_map_t::const_iterator i = mm.begin(); 131 EXPLICIT_TYPENAME method_map_t::const_iterator i_end = mm.end(); 132 for ( ; i != i_end; ++i ) 133 { 134 MethodDefExt<T> *method_def = (*i).second; 135 136 static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); 137 138 Tuple args( 2 ); 139 args[0] = Object( self, true ); 140 args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); 141 142 assert( m_module != NULL ); 143 PyObject *func = PyCFunction_NewEx 144 ( 145 &method_def->ext_meth_def, 146 new_reference_to( args ), 147 m_module 148 ); 149 150 method_def->py_method = Object( func, true ); 151 152 dict[ (*i).first ] = method_def->py_method; 153 } 154 } 155 156 protected: // Tom Malcolmson reports that derived classes need access to these methods(void)157 static method_map_t &methods( void ) 158 { 159 static method_map_t *map_of_methods = NULL; 160 if( map_of_methods == NULL ) 161 map_of_methods = new method_map_t; 162 163 return *map_of_methods; 164 } 165 166 // this invoke function must be called from within a try catch block invoke_method_noargs(void * method_def)167 virtual Object invoke_method_noargs( void *method_def ) 168 { 169 // cast up to the derived class, method_def and call 170 T *self = static_cast<T *>( this ); 171 MethodDefExt<T> *meth_def = reinterpret_cast<MethodDefExt<T> *>( method_def ); 172 173 return (self->*meth_def->ext_noargs_function)(); 174 } 175 176 // this invoke function must be called from within a try catch block invoke_method_varargs(void * method_def,const Tuple & args)177 virtual Object invoke_method_varargs( void *method_def, const Tuple &args ) 178 { 179 // cast up to the derived class, method_def and call 180 T *self = static_cast<T *>( this ); 181 MethodDefExt<T> *meth_def = reinterpret_cast<MethodDefExt<T> *>( method_def ); 182 183 return (self->*meth_def->ext_varargs_function)( args ); 184 } 185 186 // this invoke function must be called from within a try catch block invoke_method_keyword(void * method_def,const Tuple & args,const Dict & keywords)187 virtual Object invoke_method_keyword( void *method_def, const Tuple &args, const Dict &keywords ) 188 { 189 // cast up to the derived class, method_def and call 190 T *self = static_cast<T *>( this ); 191 MethodDefExt<T> *meth_def = reinterpret_cast<MethodDefExt<T> *>( method_def ); 192 193 return (self->*meth_def->ext_keyword_function)( args, keywords ); 194 } 195 196 private: 197 // 198 // prevent the compiler generating these unwanted functions 199 // 200 ExtensionModule( const ExtensionModule<T> & ); //unimplemented 201 void operator=( const ExtensionModule<T> & ); //unimplemented 202 }; 203 } // Namespace Py 204 205 206 // End of __CXX_ExtensionModule__h 207 #endif 208