ExtensionType.hxx

Go to the documentation of this file.
00001 //-----------------------------------------------------------------------------
00002 //
00003 // Copyright (c) 1998 - 2007, The Regents of the University of California
00004 // Produced at the Lawrence Livermore National Laboratory
00005 // All rights reserved.
00006 //
00007 // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The
00008 // full copyright notice is contained in the file COPYRIGHT located at the root
00009 // of the PyCXX distribution.
00010 //
00011 // Redistribution  and  use  in  source  and  binary  forms,  with  or  without
00012 // modification, are permitted provided that the following conditions are met:
00013 //
00014 //  - Redistributions of  source code must  retain the above  copyright notice,
00015 //    this list of conditions and the disclaimer below.
00016 //  - Redistributions in binary form must reproduce the above copyright notice,
00017 //    this  list of  conditions  and  the  disclaimer (as noted below)  in  the
00018 //    documentation and/or materials provided with the distribution.
00019 //  - Neither the name of the UC/LLNL nor  the names of its contributors may be
00020 //    used to  endorse or  promote products derived from  this software without
00021 //    specific prior written permission.
00022 //
00023 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS "AS IS"
00024 // AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE
00025 // IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE
00026 // ARE  DISCLAIMED.  IN  NO  EVENT  SHALL  THE  REGENTS  OF  THE  UNIVERSITY OF
00027 // CALIFORNIA, THE U.S.  DEPARTMENT  OF  ENERGY OR CONTRIBUTORS BE  LIABLE  FOR
00028 // ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR CONSEQUENTIAL
00029 // DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR
00030 // SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER
00031 // CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT
00032 // LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY
00033 // OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00034 // DAMAGE.
00035 //
00036 //-----------------------------------------------------------------------------
00037 
00038 #ifndef __CXX_ExtensionClass__h
00039 #define __CXX_ExtensionClass__h
00040 
00041 #define PYCXX_NOARGS_METHOD_NAME( NAME ) _callNoArgsMethod__##NAME
00042 #define PYCXX_VARARGS_METHOD_NAME( NAME ) _callVarArgsMethod__##NAME
00043 #define PYCXX_KEYWORDS_METHOD_NAME( NAME ) _callKeywordsMethod__##NAME
00044 
00045 #define PYCXX_NOARGS_METHOD_DECL( CLS, NAME ) \
00046     static PyObject *PYCXX_NOARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *, PyObject * ) \
00047     { \
00048         try \
00049         { \
00050             Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \
00051             CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \
00052             Py::Object r( (self->NAME)() ); \
00053             return Py::new_reference_to( r.ptr() ); \
00054         } \
00055         catch( Py::Exception & ) \
00056         { \
00057             return 0; \
00058         } \
00059     }
00060 #define PYCXX_VARARGS_METHOD_DECL( CLS, NAME ) \
00061     static PyObject *PYCXX_VARARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject * ) \
00062     { \
00063         try \
00064         { \
00065             Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \
00066             CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \
00067             Py::Tuple a( _a ); \
00068             Py::Object r( (self->NAME)( a ) ); \
00069             return Py::new_reference_to( r.ptr() ); \
00070         } \
00071         catch( Py::Exception & ) \
00072         { \
00073             return 0; \
00074         } \
00075     }
00076 #define PYCXX_KEYWORDS_METHOD_DECL( CLS, NAME ) \
00077     static PyObject *PYCXX_KEYWORDS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject *_k ) \
00078     { \
00079         try \
00080         { \
00081             Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \
00082             CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \
00083             Py::Tuple a( _a ); \
00084             Py::Dict k; \
00085             if( _k != NULL ) \
00086                 k = _k; \
00087             Py::Object r( (self->NAME)( a, k ) ); \
00088             return Py::new_reference_to( r.ptr() ); \
00089         } \
00090         catch( Py::Exception & ) \
00091         { \
00092             return 0; \
00093         } \
00094     }
00095 
00096 // need to support METH_STATIC and METH_CLASS
00097 
00098 #define PYCXX_ADD_NOARGS_METHOD( PYNAME, NAME, docs ) \
00099     add_method( #PYNAME, (PyCFunction)PYCXX_NOARGS_METHOD_NAME( NAME ), METH_NOARGS, docs )
00100 #define PYCXX_ADD_VARARGS_METHOD( PYNAME, NAME, docs ) \
00101     add_method( #PYNAME, (PyCFunction)PYCXX_VARARGS_METHOD_NAME( NAME ), METH_VARARGS, docs )
00102 #define PYCXX_ADD_KEYWORDS_METHOD( PYNAME, NAME, docs ) \
00103     add_method( #PYNAME, (PyCFunction)PYCXX_KEYWORDS_METHOD_NAME( NAME ), METH_VARARGS | METH_KEYWORDS, docs )
00104 
00105 namespace Py
00106 {
00107     extern PythonExtensionBase *getPythonExtensionBase( PyObject *self );
00108 
00109     struct PythonClassInstance
00110     {
00111         PyObject_HEAD
00112         PythonExtensionBase *m_pycxx_object;
00113     };
00114 
00115 
00116     class PYCXX_EXPORT ExtensionClassMethodsTable
00117     {
00118     public:
00119         ExtensionClassMethodsTable()
00120         : m_methods_table( new PyMethodDef[ METHOD_TABLE_SIZE_INCREMENT ] )
00121         , m_methods_used( 0 )
00122         , m_methods_size( METHOD_TABLE_SIZE_INCREMENT )
00123         {
00124         }
00125 
00126         ~ExtensionClassMethodsTable()
00127         {
00128             delete m_methods_table;
00129         }
00130 
00131         // check that all methods added are unique
00132         void check_unique_method_name( const char *_name )
00133         {
00134             std::string name( _name );
00135             for( int i=0; i<m_methods_used; i++ )
00136             {
00137                 if( name == m_methods_table[i].ml_name )
00138                 {
00139                     throw AttributeError( name );
00140                 }
00141             }
00142         }
00143         PyMethodDef *add_method( const char *name, PyCFunction function, int flags, const char *doc )
00144         {
00145             check_unique_method_name( name );
00146 
00147             // see if there is enough space for one more method
00148             if( m_methods_used == (m_methods_size-1) )
00149             {
00150                 PyMethodDef *old_mt = m_methods_table;
00151                 m_methods_size += METHOD_TABLE_SIZE_INCREMENT;
00152                 PyMethodDef *new_mt = new PyMethodDef[ m_methods_size ];
00153                 for( int i=0; i<m_methods_used; i++ )
00154                 {
00155                     new_mt[ i ] = old_mt[ i ];
00156                 }
00157                 delete[] old_mt;
00158                 m_methods_table = new_mt;
00159             }
00160 
00161             // add method into the table
00162             PyMethodDef *p = &m_methods_table[ m_methods_used ];
00163             p->ml_name = const_cast<char *>( name );
00164             p->ml_meth = function;
00165             p->ml_flags = flags;
00166             p->ml_doc = const_cast<char *>( doc );
00167 
00168             m_methods_used++;
00169             p++;
00170 
00171             // add the sentinel marking the table end
00172             p->ml_name = NULL;
00173             p->ml_meth = NULL;
00174             p->ml_flags = 0;
00175             p->ml_doc = NULL;
00176 
00177             return m_methods_table;
00178         }
00179 
00180     private:
00181         enum {METHOD_TABLE_SIZE_INCREMENT = 1};
00182         PyMethodDef *m_methods_table;
00183         int m_methods_used;
00184         int m_methods_size;
00185     };
00186 
00187     template<TEMPLATE_TYPENAME T> class PythonClass
00188     : public PythonExtensionBase
00189     {
00190     protected:
00191         explicit PythonClass( PythonClassInstance *self, Tuple &args, Dict &kwds )
00192         : PythonExtensionBase()
00193         , m_class_instance( self )
00194         {
00195         }
00196 
00197         virtual ~PythonClass()
00198         {} 
00199 
00200         static ExtensionClassMethodsTable &methodTable()
00201         {
00202             static ExtensionClassMethodsTable *method_table;
00203             if( method_table == NULL )
00204                 method_table = new ExtensionClassMethodsTable;
00205             return *method_table;
00206         }
00207 
00208         static void add_method( const char *name, PyCFunction function, int flags, const char *doc=NULL )
00209         {
00210             behaviors().set_methods( methodTable().add_method( name, function, flags, doc ) );
00211         }
00212 
00213         static PythonType &behaviors()
00214         {
00215             static PythonType *p;
00216             if( p == NULL ) 
00217             {
00218 #if defined( _CPPRTTI ) || defined( __GNUG__ )
00219                 const char *default_name = (typeid( T )).name();
00220 #else
00221                 const char *default_name = "unknown";
00222 #endif
00223                 p = new PythonType( sizeof( T ), 0, default_name );
00224                 p->set_tp_new( extension_object_new );
00225                 p->set_tp_init( extension_object_init );
00226                 p->set_tp_dealloc( extension_object_deallocator );
00227                 // we are a class
00228                 p->supportClass();
00229 
00230                 // always support get and set attr
00231                 p->supportGetattro();
00232                 p->supportSetattro();
00233             }
00234 
00235             return *p;
00236         }
00237 
00238         static PyObject *extension_object_new( PyTypeObject *subtype, PyObject *args, PyObject *kwds )
00239         {
00240 #ifdef PYCXX_DEBUG
00241             std::cout << "extension_object_new()" << std::endl;
00242 #endif
00243             PythonClassInstance *o = reinterpret_cast<PythonClassInstance *>( subtype->tp_alloc( subtype, 0 ) );
00244             if( o == NULL )
00245                 return NULL;
00246 
00247             o->m_pycxx_object = NULL;
00248 
00249             PyObject *self = reinterpret_cast<PyObject *>( o );
00250 #ifdef PYCXX_DEBUG
00251             std::cout << "extension_object_new() => self=0x" << std::hex << reinterpret_cast< unsigned int >( self ) << std::dec << std::endl;
00252 #endif
00253             return self;
00254         }
00255 
00256         static int extension_object_init( PyObject *_self, PyObject *args_, PyObject *kwds_ )
00257         {
00258             try
00259             {
00260                 Py::Tuple args( args_ );
00261                 Py::Dict kwds;
00262                 if( kwds_ != NULL )
00263                     kwds = kwds_;
00264 
00265                 PythonClassInstance *self = reinterpret_cast<PythonClassInstance *>( _self );
00266 #ifdef PYCXX_DEBUG
00267                 std::cout << "extension_object_init( self=0x" << std::hex << reinterpret_cast< unsigned int >( self ) << std::dec << " )" << std::endl;
00268                 std::cout << "    self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->m_pycxx_object ) << std::dec << std::endl;
00269 #endif
00270 
00271                 if( self->m_pycxx_object == NULL )
00272                 {
00273                     self->m_pycxx_object = new T( self, args, kwds );
00274 #ifdef PYCXX_DEBUG
00275                     std::cout << "    self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->m_pycxx_object ) << std::dec << std::endl;
00276 #endif
00277                 }
00278                 else
00279                 {
00280 #ifdef PYCXX_DEBUG
00281                     std::cout << "    reinit - self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->m_pycxx_object ) << std::dec << std::endl;
00282 #endif
00283                     self->m_pycxx_object->reinit( args, kwds );
00284                 }
00285             }
00286             catch( Exception & )
00287             {
00288                 return -1;
00289             }
00290             return 0;
00291         }
00292 
00293         static void extension_object_deallocator( PyObject *_self )
00294         {
00295             PythonClassInstance *self = reinterpret_cast< PythonClassInstance * >( _self );
00296 #ifdef PYCXX_DEBUG
00297             std::cout << "extension_object_deallocator( self=0x" << std::hex << reinterpret_cast< unsigned int >( self ) << std::dec << " )" << std::endl;
00298             std::cout << "    self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->m_pycxx_object ) << std::dec << std::endl;
00299 #endif
00300             delete self->m_pycxx_object;
00301             _self->ob_type->tp_free( _self );
00302         }
00303 
00304     public:
00305         static PyTypeObject *type_object()
00306         {
00307             return behaviors().type_object();
00308         }
00309 
00310         static Object type()
00311         {
00312             return Object( reinterpret_cast<PyObject *>( behaviors().type_object() ) );
00313         }
00314 
00315         static bool check( PyObject *p )
00316         {
00317             // is p like me?
00318             return p->ob_type == type_object();
00319         }
00320 
00321         static bool check( const Object &ob )
00322         {
00323             return check( ob.ptr() );
00324         }
00325 
00326         virtual PyObject *selfPtr()
00327         {
00328             return reinterpret_cast<PyObject *>( m_class_instance );
00329         }
00330 
00331         virtual Object self()
00332         {
00333             return Object( reinterpret_cast<PyObject *>( m_class_instance ) );
00334         }
00335 
00336     protected:
00337     private:
00338         PythonClassInstance *m_class_instance;
00339 
00340     private:
00341         //
00342         // prevent the compiler generating these unwanted functions
00343         //
00344         explicit PythonClass( const PythonClass<T> &other );
00345         void operator=( const PythonClass<T> &rhs );
00346     };
00347 
00348     //
00349     // ExtensionObject<T> is an Object that will accept only T's.
00350     //
00351     template<TEMPLATE_TYPENAME T>
00352     class PythonClassObject: public Object
00353     {
00354     public:
00355 
00356         explicit PythonClassObject( PyObject *pyob )
00357         : Object( pyob )
00358         {
00359             validate();
00360         }
00361 
00362         PythonClassObject( const PythonClassObject<T> &other )
00363         : Object( *other )
00364         {
00365             validate();
00366         }
00367 
00368         PythonClassObject( const Object &other )
00369         : Object( *other )
00370         {
00371             validate();
00372         }
00373 
00374         PythonClassObject &operator=( const Object &rhs )
00375         {
00376             *this = *rhs;
00377             return *this;
00378         }
00379 
00380         PythonClassObject &operator=( PyObject *rhsp )
00381         {
00382             if( ptr() != rhsp )
00383                 set( rhsp );
00384             return *this;
00385         }
00386 
00387         virtual bool accepts( PyObject *pyob ) const
00388         {
00389             return( pyob && T::check( pyob ) );
00390         }
00391 
00392         //
00393         //    Obtain a pointer to the PythonExtension object
00394         //
00395         T *getCxxObject( void )
00396         {
00397             return dynamic_cast< T * >( getPythonExtensionBase( ptr() ) );
00398         }
00399     };
00400 } // Namespace Py
00401 
00402 // End of __CXX_ExtensionClass__h
00403 #endif

Generated on Wed Nov 23 19:00:10 2011 for FreeCAD by  doxygen 1.6.1