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