You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/kross/python/cxx/Extensions.hxx

757 lines
19 KiB

//----------------------------------*-C++-*----------------------------------//
// Copyright 1998 The Regents of the University of California.
// All rights reserved. See LEGAL.LLNL for full text and disclaimer.
//---------------------------------------------------------------------------//
#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 "Config.hxx"
#include "Objects.hxx"
extern "C"
{
extern PyObject py_object_initializer;
}
#include <vector>
#include <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 );
};
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<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 );
typedef std::map<std::string,MethodDefExt<T> *> method_map_t;
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();
typename method_map_t::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;
void name (const char* nam);
void doc (const char* d);
void dealloc(void (*f)(PyObject*));
void supportPrint(void);
void supportGetattr(void);
void supportSetattr(void);
void supportGetattro(void);
void supportSetattro(void);
void supportCompare(void);
void supportRepr(void);
void supportStr(void);
void supportHash(void);
void supportCall(void);
void supportSequenceType(void);
void supportMappingType(void);
void supportNumberType(void);
void 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 repr();
virtual Object str();
virtual long hash();
virtual Object call( const Object &, const Object & );
// Sequence methods
virtual int sequence_length();
virtual Object sequence_concat( const Object & );
virtual Object sequence_repeat( int );
virtual Object sequence_item( int );
virtual Object sequence_slice( int, int );
virtual int sequence_ass_item( int, const Object & );
virtual int sequence_ass_slice( int, int, 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 int buffer_getreadbuffer( int, void** );
virtual int buffer_getwritebuffer( int, void** );
virtual int buffer_getsegcount( int* );
private:
void missing_method( void );
static PyObject *method_call_handler( PyObject *self, PyObject *args );
};
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 )
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 );
typedef std::map<std::string,MethodDefExt<T> *> method_map_t;
// 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 );
}
else 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();
// }
else
{
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();
if( name == "__methods__" )
{
List methods;
for( typename method_map_t::iterator i = mm.begin(); i != mm.end(); ++i )
methods.append( String( (*i).first ) );
return methods;
}
// see if name exists
if( mm.find( name ) == mm.end() )
throw AttributeError( "method '" + name + "' does not exist." );
Tuple self( 2 );
self[0] = Object( this );
self[1] = String( name );
MethodDefExt<T> *method_definition = mm[ name ];
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();
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;
}
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();
MethodDefExt<T> *meth_def = mm[ name ];
if( meth_def == NULL )
return 0;
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();
MethodDefExt<T> *meth_def = mm[ name ];
if( meth_def == NULL )
return 0;
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<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