Former-commit-id:9f19e3f712
[formerly 64fa9254b946eae7e61bbc3f513b7c3696c4f54f] Former-commit-id:06a8b51d6d
928 lines
29 KiB
C++
Executable file
928 lines
29 KiB
C++
Executable file
//-----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) 1998 - 2007, The Regents of the University of California
|
|
// Produced at the Lawrence Livermore National Laboratory
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The
|
|
// full copyright notice is contained in the file COPYRIGHT located at the root
|
|
// of the PyCXX distribution.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// - Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the disclaimer below.
|
|
// - Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the disclaimer (as noted below) in the
|
|
// documentation and/or materials provided with the distribution.
|
|
// - Neither the name of the UC/LLNL nor the names of its contributors may be
|
|
// used to endorse or promote products derived from this software without
|
|
// specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF
|
|
// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR
|
|
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
// DAMAGE.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifndef __CXX_Extensions__h
|
|
#define __CXX_Extensions__h
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
// disable warning C4786: symbol greater than 255 character,
|
|
// okay to ignore
|
|
#pragma warning(disable: 4786)
|
|
#endif
|
|
|
|
#include "CXX/WrapPython.h"
|
|
#include "CXX/Version.hxx"
|
|
#include "CXX/Config.hxx"
|
|
#include "CXX/Objects.hxx"
|
|
|
|
extern "C"
|
|
{
|
|
extern PyObject py_object_initializer;
|
|
}
|
|
|
|
#include <vector>
|
|
|
|
// std::map / hash_map selection and declarations ----------------------------
|
|
#if !defined( PYCXX_USING_HASH_MAP )
|
|
|
|
#include <map>
|
|
|
|
#else
|
|
|
|
#if defined( __GNUC__) && !defined( _STLPORT_VERSION )
|
|
#include <ext/hash_map>
|
|
#else
|
|
#include <hash_map>
|
|
#endif
|
|
#if defined( _STLPORT_VERSION )
|
|
#define __PYCXX_HASHMAP_NAMESPACE std
|
|
using namespace std;
|
|
#elif defined ( _MSC_VER ) && !defined( __INTEL_COMPILER ) && !defined( __ICC ) && !defined( __ICL ) && !defined( __ECC )
|
|
#define __PYCXX_HASHMAP_NAMESPACE stdext
|
|
using namespace stdext;
|
|
#elif defined( __INTEL_COMPILER ) || defined( __ICC ) || defined( __ICL ) || defined( __ECC )
|
|
#define __PYCXX_HASHMAP_NAMESPACE stdext
|
|
using namespace stdext;
|
|
#elif defined( __GNUC__ )
|
|
#define __PYCXX_HASHMAP_NAMESPACE __gnu_cxx
|
|
using namespace __gnu_cxx;
|
|
#else
|
|
#define __PYCXX_HASHMAP_NAMESPACE std
|
|
using namespace std;
|
|
#endif
|
|
|
|
class __pycxx_str_hash_func
|
|
{
|
|
public:
|
|
enum
|
|
{
|
|
// parameters for hash table
|
|
bucket_size = 4, // 0 < bucket_size
|
|
min_buckets = 8 // min_buckets = 2 ^^ N, 0 < N
|
|
};
|
|
|
|
// http://www.azillionmonkeys.com/qed/hash.html
|
|
size_t operator()( const std::string &str ) const
|
|
{
|
|
const unsigned char * data = reinterpret_cast<const unsigned char *>( str.c_str() );
|
|
int len = (int)str.length();
|
|
unsigned int hash = len;
|
|
unsigned int tmp;
|
|
int rem;
|
|
|
|
if (len <= 0 || data == NULL)
|
|
return 0;
|
|
|
|
rem = len & 3;
|
|
len >>= 2;
|
|
|
|
/* Main loop */
|
|
for (;len > 0; len--)
|
|
{
|
|
hash += (data[1] << 8) | data[0];
|
|
tmp = (((data[3] << 8) | data[2]) << 11) ^ hash;
|
|
hash = (hash << 16) ^ tmp;
|
|
data += 2*sizeof (unsigned short);
|
|
hash += hash >> 11;
|
|
}
|
|
|
|
/* Handle end cases */
|
|
switch (rem)
|
|
{
|
|
case 3: hash += (data[1] << 8) | data[0];
|
|
hash ^= hash << 16;
|
|
hash ^= data[sizeof (unsigned short)] << 18;
|
|
hash += hash >> 11;
|
|
break;
|
|
case 2: hash += (data[1] << 8) | data[0];
|
|
hash ^= hash << 11;
|
|
hash += hash >> 17;
|
|
break;
|
|
case 1: hash += *data;
|
|
hash ^= hash << 10;
|
|
hash += hash >> 1;
|
|
}
|
|
|
|
/* Force "avalanching" of final 127 bits */
|
|
hash ^= hash << 3;
|
|
hash += hash >> 5;
|
|
hash ^= hash << 4;
|
|
hash += hash >> 17;
|
|
hash ^= hash << 25;
|
|
hash += hash >> 6;
|
|
|
|
return hash;
|
|
}
|
|
|
|
bool operator()(const std::string &str_1, const std::string &str_2) const
|
|
{
|
|
// test if str_1 ordered before str_2
|
|
return str_1 < str_2;
|
|
}
|
|
};
|
|
#endif // PYCXX_USING_HASH_MAP
|
|
// ----------------------------------------------------------------------
|
|
|
|
namespace Py
|
|
{
|
|
class ExtensionModuleBase;
|
|
|
|
// Make an Exception Type for use in raising custom exceptions
|
|
class ExtensionExceptionType : public Object
|
|
{
|
|
public:
|
|
ExtensionExceptionType();
|
|
virtual ~ExtensionExceptionType();
|
|
|
|
// call init to create the type
|
|
void init( ExtensionModuleBase &module, const std::string& name, ExtensionExceptionType &parent );
|
|
void init( ExtensionModuleBase &module, const std::string& name );
|
|
};
|
|
|
|
|
|
class MethodTable
|
|
{
|
|
public:
|
|
MethodTable();
|
|
virtual ~MethodTable();
|
|
|
|
void add(const char* method_name, PyCFunction f, const char* doc="", int flag=1);
|
|
PyMethodDef* table();
|
|
|
|
protected:
|
|
std::vector<PyMethodDef> t; // accumulator of PyMethodDef's
|
|
PyMethodDef *mt; // Actual method table produced when full
|
|
|
|
static PyMethodDef method (const char* method_name, PyCFunction f, int flags = 1, const char* doc="");
|
|
|
|
private:
|
|
//
|
|
// prevent the compiler generating these unwanted functions
|
|
//
|
|
MethodTable(const MethodTable& m); //unimplemented
|
|
void operator=(const MethodTable& m); //unimplemented
|
|
|
|
}; // end class MethodTable
|
|
|
|
extern "C"
|
|
{
|
|
typedef PyObject *(*method_varargs_call_handler_t)( PyObject *_self, PyObject *_args );
|
|
typedef PyObject *(*method_keyword_call_handler_t)( PyObject *_self, PyObject *_args, PyObject *_dict );
|
|
}
|
|
|
|
template<class T>
|
|
class MethodDefExt : public PyMethodDef
|
|
{
|
|
public:
|
|
typedef Object (T::*method_varargs_function_t)( const Tuple &args );
|
|
typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws );
|
|
|
|
MethodDefExt
|
|
(
|
|
const char *_name,
|
|
method_varargs_function_t _function,
|
|
method_varargs_call_handler_t _handler,
|
|
const char *_doc
|
|
)
|
|
{
|
|
ext_meth_def.ml_name = const_cast<char *>(_name);
|
|
ext_meth_def.ml_meth = _handler;
|
|
ext_meth_def.ml_flags = METH_VARARGS;
|
|
ext_meth_def.ml_doc = const_cast<char *>(_doc);
|
|
|
|
ext_varargs_function = _function;
|
|
ext_keyword_function = NULL;
|
|
}
|
|
|
|
MethodDefExt
|
|
(
|
|
const char *_name,
|
|
method_keyword_function_t _function,
|
|
method_keyword_call_handler_t _handler,
|
|
const char *_doc
|
|
)
|
|
{
|
|
ext_meth_def.ml_name = const_cast<char *>(_name);
|
|
ext_meth_def.ml_meth = method_varargs_call_handler_t( _handler );
|
|
ext_meth_def.ml_flags = METH_VARARGS|METH_KEYWORDS;
|
|
ext_meth_def.ml_doc = const_cast<char *>(_doc);
|
|
|
|
ext_varargs_function = NULL;
|
|
ext_keyword_function = _function;
|
|
}
|
|
|
|
~MethodDefExt()
|
|
{}
|
|
|
|
PyMethodDef ext_meth_def;
|
|
method_varargs_function_t ext_varargs_function;
|
|
method_keyword_function_t ext_keyword_function;
|
|
};
|
|
|
|
class ExtensionModuleBase
|
|
{
|
|
public:
|
|
ExtensionModuleBase( const char *name );
|
|
virtual ~ExtensionModuleBase();
|
|
|
|
Module module(void) const; // only valid after initialize() has been called
|
|
Dict moduleDictionary(void) const; // only valid after initialize() has been called
|
|
|
|
virtual Object invoke_method_keyword( const std::string &_name, const Tuple &_args, const Dict &_keywords ) = 0;
|
|
virtual Object invoke_method_varargs( const std::string &_name, const Tuple &_args ) = 0;
|
|
|
|
const std::string &name() const;
|
|
const std::string &fullName() const;
|
|
|
|
protected:
|
|
// Initialize the module
|
|
void initialize( const char *module_doc );
|
|
|
|
const std::string module_name;
|
|
const std::string full_module_name;
|
|
MethodTable method_table;
|
|
|
|
private:
|
|
|
|
//
|
|
// prevent the compiler generating these unwanted functions
|
|
//
|
|
ExtensionModuleBase( const ExtensionModuleBase & ); //unimplemented
|
|
void operator=( const ExtensionModuleBase & ); //unimplemented
|
|
|
|
};
|
|
|
|
extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords );
|
|
extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args );
|
|
extern "C" void do_not_dealloc( void * );
|
|
|
|
|
|
template<TEMPLATE_TYPENAME T>
|
|
class ExtensionModule : public ExtensionModuleBase
|
|
{
|
|
public:
|
|
ExtensionModule( const char *name )
|
|
: ExtensionModuleBase( name )
|
|
{}
|
|
virtual ~ExtensionModule()
|
|
{}
|
|
|
|
protected:
|
|
typedef Object (T::*method_varargs_function_t)( const Tuple &args );
|
|
typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws );
|
|
|
|
#if defined( PYCXX_USING_HASH_MAP )
|
|
typedef __PYCXX_HASHMAP_NAMESPACE::hash_map<std::string, MethodDefExt<T> *, __pycxx_str_hash_func> method_map_t;
|
|
#else
|
|
typedef std::map<std::string,MethodDefExt<T> *> method_map_t;
|
|
#endif
|
|
|
|
static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" )
|
|
{
|
|
method_map_t &mm = methods();
|
|
|
|
MethodDefExt<T> *method_definition = new MethodDefExt<T>
|
|
(
|
|
name,
|
|
function,
|
|
method_varargs_call_handler,
|
|
doc
|
|
);
|
|
|
|
mm[std::string( name )] = method_definition;
|
|
}
|
|
|
|
static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" )
|
|
{
|
|
method_map_t &mm = methods();
|
|
|
|
MethodDefExt<T> *method_definition = new MethodDefExt<T>
|
|
(
|
|
name,
|
|
function,
|
|
method_keyword_call_handler,
|
|
doc
|
|
);
|
|
|
|
mm[std::string( name )] = method_definition;
|
|
}
|
|
|
|
void initialize( const char *module_doc="" )
|
|
{
|
|
ExtensionModuleBase::initialize( module_doc );
|
|
Dict dict( moduleDictionary() );
|
|
|
|
//
|
|
// put each of the methods into the modules dictionary
|
|
// so that we get called back at the function in T.
|
|
//
|
|
method_map_t &mm = methods();
|
|
EXPLICIT_TYPENAME method_map_t::const_iterator i;
|
|
|
|
for( i=mm.begin(); i != mm.end(); ++i )
|
|
{
|
|
MethodDefExt<T> *method_definition = (*i).second;
|
|
|
|
static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc );
|
|
|
|
Tuple args( 2 );
|
|
args[0] = Object( self );
|
|
args[1] = String( (*i).first );
|
|
|
|
PyObject *func = PyCFunction_New
|
|
(
|
|
&method_definition->ext_meth_def,
|
|
new_reference_to( args )
|
|
);
|
|
|
|
dict[ (*i).first ] = Object( func );
|
|
}
|
|
}
|
|
|
|
protected: // Tom Malcolmson reports that derived classes need access to these
|
|
|
|
static method_map_t &methods(void)
|
|
{
|
|
static method_map_t *map_of_methods = NULL;
|
|
if( map_of_methods == NULL )
|
|
map_of_methods = new method_map_t;
|
|
|
|
return *map_of_methods;
|
|
}
|
|
|
|
|
|
// this invoke function must be called from within a try catch block
|
|
virtual Object invoke_method_keyword( const std::string &name, const Tuple &args, const Dict &keywords )
|
|
{
|
|
method_map_t &mm = methods();
|
|
MethodDefExt<T> *meth_def = mm[ name ];
|
|
if( meth_def == NULL )
|
|
{
|
|
std::string error_msg( "CXX - cannot invoke keyword method named " );
|
|
error_msg += name;
|
|
throw RuntimeError( error_msg );
|
|
}
|
|
|
|
// cast up to the derived class
|
|
T *self = static_cast<T *>(this);
|
|
|
|
return (self->*meth_def->ext_keyword_function)( args, keywords );
|
|
}
|
|
|
|
// this invoke function must be called from within a try catch block
|
|
virtual Object invoke_method_varargs( const std::string &name, const Tuple &args )
|
|
{
|
|
method_map_t &mm = methods();
|
|
MethodDefExt<T> *meth_def = mm[ name ];
|
|
if( meth_def == NULL )
|
|
{
|
|
std::string error_msg( "CXX - cannot invoke varargs method named " );
|
|
error_msg += name;
|
|
throw RuntimeError( error_msg );
|
|
}
|
|
|
|
// cast up to the derived class
|
|
T *self = static_cast<T *>(this);
|
|
|
|
return (self->*meth_def->ext_varargs_function)( args );
|
|
}
|
|
|
|
private:
|
|
//
|
|
// prevent the compiler generating these unwanted functions
|
|
//
|
|
ExtensionModule( const ExtensionModule<T> & ); //unimplemented
|
|
void operator=( const ExtensionModule<T> & ); //unimplemented
|
|
};
|
|
|
|
|
|
class PythonType
|
|
{
|
|
public:
|
|
// if you define one sequence method you must define
|
|
// all of them except the assigns
|
|
|
|
PythonType (size_t base_size, int itemsize, const char *default_name );
|
|
virtual ~PythonType ();
|
|
|
|
const char *getName () const;
|
|
const char *getDoc () const;
|
|
|
|
PyTypeObject* type_object () const;
|
|
PythonType & name (const char* nam);
|
|
PythonType & doc (const char* d);
|
|
PythonType & dealloc(void (*f)(PyObject*));
|
|
|
|
PythonType & supportPrint(void);
|
|
PythonType & supportGetattr(void);
|
|
PythonType & supportSetattr(void);
|
|
PythonType & supportGetattro(void);
|
|
PythonType & supportSetattro(void);
|
|
PythonType & supportCompare(void);
|
|
#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1)
|
|
PythonType & supportRichCompare(void);
|
|
#endif
|
|
PythonType & supportRepr(void);
|
|
PythonType & supportStr(void);
|
|
PythonType & supportHash(void);
|
|
PythonType & supportCall(void);
|
|
PythonType & supportIter(void);
|
|
|
|
PythonType & supportSequenceType(void);
|
|
PythonType & supportMappingType(void);
|
|
PythonType & supportNumberType(void);
|
|
PythonType & supportBufferType(void);
|
|
|
|
protected:
|
|
PyTypeObject *table;
|
|
PySequenceMethods *sequence_table;
|
|
PyMappingMethods *mapping_table;
|
|
PyNumberMethods *number_table;
|
|
PyBufferProcs *buffer_table;
|
|
|
|
void init_sequence();
|
|
void init_mapping();
|
|
void init_number();
|
|
void init_buffer();
|
|
|
|
private:
|
|
//
|
|
// prevent the compiler generating these unwanted functions
|
|
//
|
|
PythonType (const PythonType& tb); // unimplemented
|
|
void operator=(const PythonType& t); // unimplemented
|
|
|
|
}; // end of PythonType
|
|
|
|
|
|
|
|
// Class PythonExtension is what you inherit from to create
|
|
// a new Python extension type. You give your class itself
|
|
// as the template paramter.
|
|
|
|
// There are two ways that extension objects can get destroyed.
|
|
// 1. Their reference count goes to zero
|
|
// 2. Someone does an explicit delete on a pointer.
|
|
// In (1) the problem is to get the destructor called
|
|
// We register a special deallocator in the Python type object
|
|
// (see behaviors()) to do this.
|
|
// In (2) there is no problem, the dtor gets called.
|
|
|
|
// PythonExtension does not use the usual Python heap allocator,
|
|
// instead using new/delete. We do the setting of the type object
|
|
// and reference count, usually done by PyObject_New, in the
|
|
// base class ctor.
|
|
|
|
// This special deallocator does a delete on the pointer.
|
|
|
|
|
|
class PythonExtensionBase : public PyObject
|
|
{
|
|
public:
|
|
PythonExtensionBase();
|
|
virtual ~PythonExtensionBase();
|
|
|
|
public:
|
|
virtual int print( FILE *, int );
|
|
virtual Object getattr( const char * ) = 0;
|
|
virtual int setattr( const char *, const Object & );
|
|
virtual Object getattro( const Object & );
|
|
virtual int setattro( const Object &, const Object & );
|
|
virtual int compare( const Object & );
|
|
virtual Object rich_compare( const Object &, int op );
|
|
virtual Object repr();
|
|
virtual Object str();
|
|
virtual long hash();
|
|
virtual Object call( const Object &, const Object & );
|
|
virtual Object iter();
|
|
virtual PyObject* iternext();
|
|
|
|
// Sequence methods
|
|
virtual int sequence_length();
|
|
virtual Object sequence_concat( const Object & );
|
|
virtual Object sequence_repeat( Py_ssize_t );
|
|
virtual Object sequence_item( Py_ssize_t );
|
|
virtual Object sequence_slice( Py_ssize_t, Py_ssize_t );
|
|
virtual int sequence_ass_item( Py_ssize_t, const Object & );
|
|
virtual int sequence_ass_slice( Py_ssize_t, Py_ssize_t, const Object & );
|
|
|
|
// Mapping
|
|
virtual int mapping_length();
|
|
virtual Object mapping_subscript( const Object & );
|
|
virtual int mapping_ass_subscript( const Object &, const Object & );
|
|
|
|
// Number
|
|
virtual int number_nonzero();
|
|
virtual Object number_negative();
|
|
virtual Object number_positive();
|
|
virtual Object number_absolute();
|
|
virtual Object number_invert();
|
|
virtual Object number_int();
|
|
virtual Object number_float();
|
|
virtual Object number_long();
|
|
virtual Object number_oct();
|
|
virtual Object number_hex();
|
|
virtual Object number_add( const Object & );
|
|
virtual Object number_subtract( const Object & );
|
|
virtual Object number_multiply( const Object & );
|
|
virtual Object number_divide( const Object & );
|
|
virtual Object number_remainder( const Object & );
|
|
virtual Object number_divmod( const Object & );
|
|
virtual Object number_lshift( const Object & );
|
|
virtual Object number_rshift( const Object & );
|
|
virtual Object number_and( const Object & );
|
|
virtual Object number_xor( const Object & );
|
|
virtual Object number_or( const Object & );
|
|
virtual Object number_power( const Object &, const Object & );
|
|
|
|
// Buffer
|
|
virtual Py_ssize_t buffer_getreadbuffer( Py_ssize_t, void** );
|
|
virtual Py_ssize_t buffer_getwritebuffer( Py_ssize_t, void** );
|
|
virtual Py_ssize_t buffer_getsegcount( Py_ssize_t* );
|
|
|
|
private:
|
|
void missing_method( void );
|
|
static PyObject *method_call_handler( PyObject *self, PyObject *args );
|
|
};
|
|
|
|
template<TEMPLATE_TYPENAME T>
|
|
class PythonExtension: public PythonExtensionBase
|
|
{
|
|
public:
|
|
static PyTypeObject* type_object()
|
|
{
|
|
return behaviors().type_object();
|
|
}
|
|
|
|
static int check( PyObject *p )
|
|
{
|
|
// is p like me?
|
|
return p->ob_type == type_object();
|
|
}
|
|
|
|
static int check( const Object& ob )
|
|
{
|
|
return check( ob.ptr());
|
|
}
|
|
|
|
|
|
//
|
|
// every object needs getattr implemented
|
|
// to support methods
|
|
//
|
|
virtual Object getattr( const char *name )
|
|
{
|
|
return getattr_methods( name );
|
|
}
|
|
|
|
protected:
|
|
explicit PythonExtension()
|
|
: PythonExtensionBase()
|
|
{
|
|
#ifdef PyObject_INIT
|
|
(void)PyObject_INIT( this, type_object() );
|
|
#else
|
|
ob_refcnt = 1;
|
|
ob_type = type_object();
|
|
#endif
|
|
|
|
// every object must support getattr
|
|
behaviors().supportGetattr();
|
|
}
|
|
|
|
virtual ~PythonExtension()
|
|
{}
|
|
|
|
static PythonType &behaviors()
|
|
{
|
|
static PythonType* p;
|
|
if( p == NULL )
|
|
{
|
|
#if defined( _CPPRTTI ) || defined(__GNUG__)
|
|
const char *default_name = (typeid ( T )).name();
|
|
#else
|
|
const char *default_name = "unknown";
|
|
#endif
|
|
p = new PythonType( sizeof( T ), 0, default_name );
|
|
p->dealloc( extension_object_deallocator );
|
|
}
|
|
|
|
return *p;
|
|
}
|
|
|
|
|
|
typedef Object (T::*method_varargs_function_t)( const Tuple &args );
|
|
typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws );
|
|
|
|
#if defined( PYCXX_USING_HASH_MAP )
|
|
typedef __PYCXX_HASHMAP_NAMESPACE::hash_map<std::string, MethodDefExt<T> *, __pycxx_str_hash_func> method_map_t;
|
|
#else
|
|
typedef std::map<std::string,MethodDefExt<T> *> method_map_t;
|
|
#endif
|
|
|
|
// support the default attributes, __name__, __doc__ and methods
|
|
virtual Object getattr_default( const char *_name )
|
|
{
|
|
std::string name( _name );
|
|
|
|
if( name == "__name__" && type_object()->tp_name != NULL )
|
|
{
|
|
return Py::String( type_object()->tp_name );
|
|
}
|
|
if( name == "__doc__" && type_object()->tp_doc != NULL )
|
|
{
|
|
return Py::String( type_object()->tp_doc );
|
|
}
|
|
|
|
// trying to fake out being a class for help()
|
|
// else if( name == "__bases__" )
|
|
// {
|
|
// return Py::Tuple(0);
|
|
// }
|
|
// else if( name == "__module__" )
|
|
// {
|
|
// return Py::Nothing();
|
|
// }
|
|
// else if( name == "__dict__" )
|
|
// {
|
|
// return Py::Dict();
|
|
// }
|
|
|
|
return getattr_methods( _name );
|
|
}
|
|
|
|
// turn a name into function object
|
|
virtual Object getattr_methods( const char *_name )
|
|
{
|
|
std::string name( _name );
|
|
|
|
method_map_t &mm = methods();
|
|
|
|
EXPLICIT_TYPENAME method_map_t::const_iterator i;
|
|
|
|
if( name == "__methods__" )
|
|
{
|
|
List methods;
|
|
|
|
for( i = mm.begin(); i != mm.end(); ++i )
|
|
methods.append( String( (*i).first ) );
|
|
|
|
return methods;
|
|
}
|
|
|
|
// see if name exists and get entry with method
|
|
i = mm.find( name );
|
|
if( i == mm.end() )
|
|
throw AttributeError( name );
|
|
|
|
Tuple self( 2 );
|
|
|
|
self[0] = Object( this );
|
|
self[1] = String( name );
|
|
|
|
MethodDefExt<T> *method_definition = i->second;
|
|
|
|
PyObject *func = PyCFunction_New( &method_definition->ext_meth_def, self.ptr() );
|
|
|
|
return Object(func, true);
|
|
}
|
|
|
|
static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" )
|
|
{
|
|
method_map_t &mm = methods();
|
|
|
|
// check that all methods added are unique
|
|
EXPLICIT_TYPENAME method_map_t::const_iterator i;
|
|
i = mm.find( name );
|
|
if( i != mm.end() )
|
|
throw AttributeError( name );
|
|
|
|
MethodDefExt<T> *method_definition = new MethodDefExt<T>
|
|
(
|
|
name,
|
|
function,
|
|
method_varargs_call_handler,
|
|
doc
|
|
);
|
|
|
|
mm[std::string( name )] = method_definition;
|
|
}
|
|
|
|
static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" )
|
|
{
|
|
method_map_t &mm = methods();
|
|
|
|
// check that all methods added are unique
|
|
EXPLICIT_TYPENAME method_map_t::const_iterator i;
|
|
i = mm.find( name );
|
|
if( i != mm.end() )
|
|
throw AttributeError( name );
|
|
|
|
MethodDefExt<T> *method_definition = new MethodDefExt<T>
|
|
(
|
|
name,
|
|
function,
|
|
method_keyword_call_handler,
|
|
doc
|
|
);
|
|
|
|
mm[std::string( name )] = method_definition;
|
|
}
|
|
|
|
private:
|
|
static method_map_t &methods(void)
|
|
{
|
|
static method_map_t *map_of_methods = NULL;
|
|
if( map_of_methods == NULL )
|
|
map_of_methods = new method_map_t;
|
|
|
|
return *map_of_methods;
|
|
}
|
|
|
|
static PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords )
|
|
{
|
|
try
|
|
{
|
|
Tuple self_and_name_tuple( _self_and_name_tuple );
|
|
|
|
PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
|
|
T *self = static_cast<T *>( self_in_cobject );
|
|
|
|
String name( self_and_name_tuple[1] );
|
|
|
|
method_map_t &mm = methods();
|
|
|
|
EXPLICIT_TYPENAME method_map_t::const_iterator i;
|
|
i = mm.find( name );
|
|
if( i == mm.end() )
|
|
return 0;
|
|
|
|
MethodDefExt<T> *meth_def = i->second;
|
|
|
|
Tuple args( _args );
|
|
|
|
// _keywords may be NULL so be careful about the way the dict is created
|
|
Dict keywords;
|
|
if( _keywords != NULL )
|
|
keywords = Dict( _keywords );
|
|
|
|
Object result( (self->*meth_def->ext_keyword_function)( args, keywords ) );
|
|
|
|
return new_reference_to( result.ptr() );
|
|
}
|
|
catch( Exception & )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args )
|
|
{
|
|
try
|
|
{
|
|
Tuple self_and_name_tuple( _self_and_name_tuple );
|
|
|
|
PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
|
|
T *self = static_cast<T *>( self_in_cobject );
|
|
|
|
String name( self_and_name_tuple[1] );
|
|
|
|
method_map_t &mm = methods();
|
|
|
|
EXPLICIT_TYPENAME method_map_t::const_iterator i;
|
|
i = mm.find( name );
|
|
if( i == mm.end() )
|
|
return 0;
|
|
|
|
MethodDefExt<T> *meth_def = i->second;
|
|
|
|
Tuple args( _args );
|
|
|
|
Object result;
|
|
|
|
// TMM: 7Jun'01 - Adding try & catch in case of STL debug-mode exceptions.
|
|
#ifdef _STLP_DEBUG
|
|
try
|
|
{
|
|
result = (self->*meth_def->ext_varargs_function)( args );
|
|
}
|
|
catch (std::__stl_debug_exception)
|
|
{
|
|
// throw cxx::RuntimeError( sErrMsg );
|
|
throw cxx::RuntimeError( "Error message not set yet." );
|
|
}
|
|
#else
|
|
result = (self->*meth_def->ext_varargs_function)( args );
|
|
#endif // _STLP_DEBUG
|
|
|
|
return new_reference_to( result.ptr() );
|
|
}
|
|
catch( Exception & )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void extension_object_deallocator ( PyObject* t )
|
|
{
|
|
delete (T *)( t );
|
|
}
|
|
|
|
//
|
|
// prevent the compiler generating these unwanted functions
|
|
//
|
|
explicit PythonExtension( const PythonExtension<T>& other );
|
|
void operator=( const PythonExtension<T>& rhs );
|
|
};
|
|
|
|
//
|
|
// ExtensionObject<T> is an Object that will accept only T's.
|
|
//
|
|
template<TEMPLATE_TYPENAME T>
|
|
class ExtensionObject: public Object
|
|
{
|
|
public:
|
|
|
|
explicit ExtensionObject ( PyObject *pyob )
|
|
: Object( pyob )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
ExtensionObject( const ExtensionObject<T>& other )
|
|
: Object( *other )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
ExtensionObject( const Object& other )
|
|
: Object( *other )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
ExtensionObject& operator= ( const Object& rhs )
|
|
{
|
|
return (*this = *rhs );
|
|
}
|
|
|
|
ExtensionObject& operator= ( PyObject* rhsp )
|
|
{
|
|
if( ptr() == rhsp )
|
|
return *this;
|
|
set( rhsp );
|
|
return *this;
|
|
}
|
|
|
|
virtual bool accepts ( PyObject *pyob ) const
|
|
{
|
|
return ( pyob && T::check( pyob ));
|
|
}
|
|
|
|
//
|
|
// Obtain a pointer to the PythonExtension object
|
|
//
|
|
T *extensionObject(void)
|
|
{
|
|
return static_cast<T *>( ptr() );
|
|
}
|
|
};
|
|
|
|
} // Namespace Py
|
|
// End of CXX_Extensions.h
|
|
#endif
|