diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /lib/kross/python/cxx | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'lib/kross/python/cxx')
-rw-r--r-- | lib/kross/python/cxx/Config.hxx | 74 | ||||
-rw-r--r-- | lib/kross/python/cxx/Exception.hxx | 212 | ||||
-rw-r--r-- | lib/kross/python/cxx/Extensions.hxx | 756 | ||||
-rw-r--r-- | lib/kross/python/cxx/IndirectPythonInterface.cxx | 550 | ||||
-rw-r--r-- | lib/kross/python/cxx/IndirectPythonInterface.hxx | 156 | ||||
-rwxr-xr-x | lib/kross/python/cxx/Legal.html | 40 | ||||
-rw-r--r-- | lib/kross/python/cxx/Makefile.am | 19 | ||||
-rw-r--r-- | lib/kross/python/cxx/Objects.hxx | 2804 | ||||
-rw-r--r-- | lib/kross/python/cxx/PyCXX.html | 2131 | ||||
-rw-r--r-- | lib/kross/python/cxx/README.html | 436 | ||||
-rw-r--r-- | lib/kross/python/cxx/Readme.Kross.txt | 16 | ||||
-rw-r--r-- | lib/kross/python/cxx/Version.txt | 1 | ||||
-rw-r--r-- | lib/kross/python/cxx/cxx_extensions.cxx | 1287 | ||||
-rw-r--r-- | lib/kross/python/cxx/cxxextensions.c | 19 | ||||
-rw-r--r-- | lib/kross/python/cxx/cxxsupport.cxx | 142 |
15 files changed, 8643 insertions, 0 deletions
diff --git a/lib/kross/python/cxx/Config.hxx b/lib/kross/python/cxx/Config.hxx new file mode 100644 index 00000000..65bbc2d3 --- /dev/null +++ b/lib/kross/python/cxx/Config.hxx @@ -0,0 +1,74 @@ +#ifndef __PyCXX_config_hh__ +#define __PyCXX_config_hh__ + +// +// Microsoft VC++ 6.0 has no traits +// +#if defined( _MSC_VER ) + +# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 + +#elif defined( __GNUC__ ) +# if __GNUC__ >= 3 +# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 +# else +# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 0 +#endif + +// +// Assume all other compilers do +// +#else + +// Macros to deal with deficiencies in compilers +# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 +#endif + +#if STANDARD_LIBRARY_HAS_ITERATOR_TRAITS +# define random_access_iterator_parent(itemtype) std::iterator<std::random_access_iterator_tag,itemtype,int> +#else +# define random_access_iterator_parent(itemtype) std::random_access_iterator<itemtype, int> +#endif + +// +// Which C++ standard is in use? +// +#if defined( _MSC_VER ) +# if _MSC_VER <= 1200 +// MSVC++ 6.0 +# define PYCXX_ISO_CPP_LIB 0 +# define STR_STREAM <strstream> +# define TEMPLATE_TYPENAME class +# else +# define PYCXX_ISO_CPP_LIB 1 +# define STR_STREAM <sstream> +# define TEMPLATE_TYPENAME typename +# endif +#elif defined( __GNUC__ ) +# if __GNUC__ >= 3 +# define PYCXX_ISO_CPP_LIB 1 +# define STR_STREAM <sstream> +# define TEMPLATE_TYPENAME typename +# else +# define PYCXX_ISO_CPP_LIB 0 +# define STR_STREAM <strstream> +# define TEMPLATE_TYPENAME class +# endif +#endif + +#if PYCXX_ISO_CPP_LIB +# define STR_STREAM <sstream> +# define OSTRSTREAM ostringstream +# define EXPLICIT_TYPENAME typename +# define EXPLICIT_CLASS class +# define TEMPLATE_TYPENAME typename +#else +# define STR_STREAM <strstream> +# define OSTRSTREAM ostrstream +# define EXPLICIT_TYPENAME +# define EXPLICIT_CLASS +# define TEMPLATE_TYPENAME class +#endif + + +#endif // __PyCXX_config_hh__ diff --git a/lib/kross/python/cxx/Exception.hxx b/lib/kross/python/cxx/Exception.hxx new file mode 100644 index 00000000..afcff489 --- /dev/null +++ b/lib/kross/python/cxx/Exception.hxx @@ -0,0 +1,212 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 1998 The Regents of the University of California. +// All rights reserved. See LEGAL.LLNL for full text and disclaimer. +//---------------------------------------------------------------------------// + +#ifndef __CXX_Exception_h +#define __CXX_Exception_h + +#include "Python.h" +#include "Config.hxx" +#include "IndirectPythonInterface.hxx" + +#include <string> +#include <iostream> + +// This mimics the Python structure, in order to minimize confusion +namespace Py + { + class ExtensionExceptionType; + + class Exception + { + public: + Exception( ExtensionExceptionType &exception, const std::string& reason ); + + explicit Exception () + {} + + Exception (const std::string& reason) + { + PyErr_SetString (Py::_Exc_RuntimeError(), reason.c_str()); + } + + Exception (PyObject* exception, const std::string& reason) + { + PyErr_SetString (exception, reason.c_str()); + } + + + void clear() // clear the error + // technically but not philosophically const + { + PyErr_Clear(); + } + }; + + + // Abstract + class StandardError: public Exception + { + protected: + explicit StandardError() + {} + }; + + class LookupError: public StandardError + { + protected: + explicit LookupError() + {} + }; + + class ArithmeticError: public StandardError + { + protected: + explicit ArithmeticError() + {} + }; + + class EnvironmentError: public StandardError + { + protected: + explicit EnvironmentError() + {} + }; + + // Concrete + + class TypeError: public StandardError + { + public: + TypeError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_TypeError(),reason.c_str()); + } + }; + + class IndexError: public LookupError + { + public: + IndexError (const std::string& reason) + : LookupError() + { + PyErr_SetString (Py::_Exc_IndexError(), reason.c_str()); + } + }; + + class AttributeError: public StandardError + { + public: + AttributeError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_AttributeError(), reason.c_str()); + } + }; + + class NameError: public StandardError + { + public: + NameError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_NameError(), reason.c_str()); + } + }; + + class RuntimeError: public StandardError + { + public: + RuntimeError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_RuntimeError(), reason.c_str()); + } + }; + + class SystemError: public StandardError + { + public: + SystemError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_SystemError(),reason.c_str()); + } + }; + + class KeyError: public LookupError + { + public: + KeyError (const std::string& reason) + : LookupError() + { + PyErr_SetString (Py::_Exc_KeyError(),reason.c_str()); + } + }; + + + class ValueError: public StandardError + { + public: + ValueError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_ValueError(), reason.c_str()); + } + }; + + class OverflowError: public ArithmeticError + { + public: + OverflowError (const std::string& reason) + : ArithmeticError() + { + PyErr_SetString (Py::_Exc_OverflowError(), reason.c_str()); + } + }; + + class ZeroDivisionError: public ArithmeticError + { + public: + ZeroDivisionError (const std::string& reason) + : ArithmeticError() + { + PyErr_SetString (Py::_Exc_ZeroDivisionError(), reason.c_str()); + } + }; + + class FloatingPointError: public ArithmeticError + { + public: + FloatingPointError (const std::string& reason) + : ArithmeticError() + { + PyErr_SetString (Py::_Exc_FloatingPointError(), reason.c_str()); + } + }; + + class MemoryError: public StandardError + { + public: + MemoryError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_MemoryError(), reason.c_str()); + } + }; + + class SystemExit: public StandardError + { + public: + SystemExit (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_SystemExit(),reason.c_str()); + } + }; + + }// Py + +#endif diff --git a/lib/kross/python/cxx/Extensions.hxx b/lib/kross/python/cxx/Extensions.hxx new file mode 100644 index 00000000..69ce9a14 --- /dev/null +++ b/lib/kross/python/cxx/Extensions.hxx @@ -0,0 +1,756 @@ +//----------------------------------*-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<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(); + EXPLICIT_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<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( EXPLICIT_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<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 diff --git a/lib/kross/python/cxx/IndirectPythonInterface.cxx b/lib/kross/python/cxx/IndirectPythonInterface.cxx new file mode 100644 index 00000000..caaa0913 --- /dev/null +++ b/lib/kross/python/cxx/IndirectPythonInterface.cxx @@ -0,0 +1,550 @@ +// +// IndirectPythonInterface.cxx +// +#undef _XOPEN_SOURCE +#include "IndirectPythonInterface.hxx" + +namespace Py +{ +bool _Buffer_Check( PyObject *op ) { return (op)->ob_type == _Buffer_Type(); } +bool _CFunction_Check( PyObject *op ) { return (op)->ob_type == _CFunction_Type(); } +bool _Class_Check( PyObject *op ) { return (op)->ob_type == _Class_Type(); } +bool _CObject_Check( PyObject *op ) { return (op)->ob_type == _CObject_Type(); } +bool _Complex_Check( PyObject *op ) { return (op)->ob_type == _Complex_Type(); } +bool _Dict_Check( PyObject *op ) { return (op)->ob_type == _Dict_Type(); } +bool _File_Check( PyObject *op ) { return (op)->ob_type == _File_Type(); } +bool _Float_Check( PyObject *op ) { return (op)->ob_type == _Float_Type(); } +bool _Function_Check( PyObject *op ) { return (op)->ob_type == _Function_Type(); } +bool _Instance_Check( PyObject *op ) { return (op)->ob_type == _Instance_Type(); } +bool _Int_Check( PyObject *op ) { return (op)->ob_type == _Int_Type(); } +bool _List_Check( PyObject *o ) { return o->ob_type == _List_Type(); } +bool _Long_Check( PyObject *op ) { return (op)->ob_type == _Long_Type(); } +bool _Method_Check( PyObject *op ) { return (op)->ob_type == _Method_Type(); } +bool _Module_Check( PyObject *op ) { return (op)->ob_type == _Module_Type(); } +bool _Range_Check( PyObject *op ) { return (op)->ob_type == _Range_Type(); } +bool _Slice_Check( PyObject *op ) { return (op)->ob_type == _Slice_Type(); } +bool _String_Check( PyObject *o ) { return o->ob_type == _String_Type(); } +bool _TraceBack_Check( PyObject *v ) { return (v)->ob_type == _TraceBack_Type(); } +bool _Tuple_Check( PyObject *op ) { return (op)->ob_type == _Tuple_Type(); } +bool _Type_Check( PyObject *op ) { return (op)->ob_type == _Type_Type(); } + +#if PY_MAJOR_VERSION >= 2 +bool _Unicode_Check( PyObject *op ) { return (op)->ob_type == _Unicode_Type(); } +#endif + + + +#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) + +#if defined(MS_WINDOWS) +#include <windows.h> + + +static HMODULE python_dll; + +static PyObject *ptr__Exc_ArithmeticError = NULL; +static PyObject *ptr__Exc_AssertionError = NULL; +static PyObject *ptr__Exc_AttributeError = NULL; +static PyObject *ptr__Exc_EnvironmentError = NULL; +static PyObject *ptr__Exc_EOFError = NULL; +static PyObject *ptr__Exc_Exception = NULL; +static PyObject *ptr__Exc_FloatingPointError = NULL; +static PyObject *ptr__Exc_ImportError = NULL; +static PyObject *ptr__Exc_IndexError = NULL; +static PyObject *ptr__Exc_IOError = NULL; +static PyObject *ptr__Exc_KeyboardInterrupt = NULL; +static PyObject *ptr__Exc_KeyError = NULL; +static PyObject *ptr__Exc_LookupError = NULL; +static PyObject *ptr__Exc_MemoryError = NULL; +static PyObject *ptr__Exc_MemoryErrorInst = NULL; +static PyObject *ptr__Exc_NameError = NULL; +static PyObject *ptr__Exc_NotImplementedError = NULL; +static PyObject *ptr__Exc_OSError = NULL; +static PyObject *ptr__Exc_OverflowError = NULL; +static PyObject *ptr__Exc_RuntimeError = NULL; +static PyObject *ptr__Exc_StandardError = NULL; +static PyObject *ptr__Exc_SyntaxError = NULL; +static PyObject *ptr__Exc_SystemError = NULL; +static PyObject *ptr__Exc_SystemExit = NULL; +static PyObject *ptr__Exc_TypeError = NULL; +static PyObject *ptr__Exc_ValueError = NULL; +static PyObject *ptr__Exc_ZeroDivisionError = NULL; + +#ifdef MS_WINDOWS +static PyObject *ptr__Exc_WindowsError = NULL; +#endif + +#if PY_MAJOR_VERSION >= 2 +static PyObject *ptr__Exc_IndentationError = NULL; +static PyObject *ptr__Exc_TabError = NULL; +static PyObject *ptr__Exc_UnboundLocalError = NULL; +static PyObject *ptr__Exc_UnicodeError = NULL; +#endif + +static PyObject *ptr__PyNone = NULL; + +static PyTypeObject *ptr__Buffer_Type = NULL; +static PyTypeObject *ptr__CFunction_Type = NULL; +static PyTypeObject *ptr__Class_Type = NULL; +static PyTypeObject *ptr__CObject_Type = NULL; +static PyTypeObject *ptr__Complex_Type = NULL; +static PyTypeObject *ptr__Dict_Type = NULL; +static PyTypeObject *ptr__File_Type = NULL; +static PyTypeObject *ptr__Float_Type = NULL; +static PyTypeObject *ptr__Function_Type = NULL; +static PyTypeObject *ptr__Instance_Type = NULL; +static PyTypeObject *ptr__Int_Type = NULL; +static PyTypeObject *ptr__List_Type = NULL; +static PyTypeObject *ptr__Long_Type = NULL; +static PyTypeObject *ptr__Method_Type = NULL; +static PyTypeObject *ptr__Module_Type = NULL; +static PyTypeObject *ptr__Range_Type = NULL; +static PyTypeObject *ptr__Slice_Type = NULL; +static PyTypeObject *ptr__String_Type = NULL; +static PyTypeObject *ptr__TraceBack_Type = NULL; +static PyTypeObject *ptr__Tuple_Type = NULL; +static PyTypeObject *ptr__Type_Type = NULL; + +#if PY_MAJOR_VERSION >= 2 +static PyTypeObject *ptr__Unicode_Type = NULL; +#endif + +static int *ptr_Py_DebugFlag = NULL; +static int *ptr_Py_InteractiveFlag = NULL; +static int *ptr_Py_OptimizeFlag = NULL; +static int *ptr_Py_NoSiteFlag = NULL; +static int *ptr_Py_TabcheckFlag = NULL; +static int *ptr_Py_VerboseFlag = NULL; + +#if PY_MAJOR_VERSION >= 2 +static int *ptr_Py_UnicodeFlag = NULL; +#endif + +static char **ptr__Py_PackageContext = NULL; + +#ifdef Py_REF_DEBUG +int *ptr_Py_RefTotal; +#endif + + +//-------------------------------------------------------------------------------- +class GetAddressException + { +public: + GetAddressException( const char *_name ) + : name( _name ) + {} + virtual ~GetAddressException() {} + const char *name; + }; + + +//-------------------------------------------------------------------------------- +static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return *(PyObject **)addr; + } + +static PyObject *GetPyObject_As_PyObjectPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (PyObject *)addr; + } + +static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return *(PyTypeObject **)addr; + } + +static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (PyTypeObject *)addr; + } + +static int *GetInt_as_IntPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (int *)addr; + } + +static char **GetCharPointer_as_CharPointerPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (char **)addr; + } + + +#ifdef _DEBUG +static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL"; +#else +static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL"; +#endif + +//-------------------------------------------------------------------------------- +bool InitialisePythonIndirectInterface() + { + char python_dll_name[sizeof(python_dll_name_format)]; + + sprintf( python_dll_name, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); + + python_dll = LoadLibrary( python_dll_name ); + if( python_dll == NULL ) + return false; + + try + { +#ifdef Py_REF_DEBUG + ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); +#endif + ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" ); + ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" ); + ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" ); + ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" ); + ptr_Py_TabcheckFlag = GetInt_as_IntPointer( "Py_TabcheckFlag" ); + ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); +#if PY_MAJOR_VERSION >= 2 + ptr_Py_UnicodeFlag = GetInt_as_IntPointer( "Py_UnicodeFlag" ); +#endif + ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); + + ptr__Exc_ArithmeticError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ArithmeticError" ); + ptr__Exc_AssertionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AssertionError" ); + ptr__Exc_AttributeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AttributeError" ); + ptr__Exc_EnvironmentError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EnvironmentError" ); + ptr__Exc_EOFError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EOFError" ); + ptr__Exc_Exception = GetPyObjectPointer_As_PyObjectPointer( "PyExc_Exception" ); + ptr__Exc_FloatingPointError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_FloatingPointError" ); + ptr__Exc_ImportError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ImportError" ); + ptr__Exc_IndexError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndexError" ); + ptr__Exc_IOError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IOError" ); + ptr__Exc_KeyboardInterrupt = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyboardInterrupt" ); + ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" ); + ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" ); + ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" ); + ptr__Exc_MemoryErrorInst = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryErrorInst" ); + ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" ); + ptr__Exc_NotImplementedError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" ); + ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" ); + ptr__Exc_OverflowError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OverflowError" ); + ptr__Exc_RuntimeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_RuntimeError" ); + ptr__Exc_StandardError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_StandardError" ); + ptr__Exc_SyntaxError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SyntaxError" ); + ptr__Exc_SystemError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemError" ); + ptr__Exc_SystemExit = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemExit" ); + ptr__Exc_TypeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TypeError" ); + ptr__Exc_ValueError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ValueError" ); +#ifdef MS_WINDOWS + ptr__Exc_WindowsError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_WindowsError" ); +#endif + ptr__Exc_ZeroDivisionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ZeroDivisionError" ); + +#if PY_MAJOR_VERSION >= 2 + ptr__Exc_IndentationError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndentationError" ); + ptr__Exc_TabError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TabError" ); + ptr__Exc_UnboundLocalError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnboundLocalError" ); + ptr__Exc_UnicodeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnicodeError" ); +#endif + ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); + + ptr__Buffer_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBuffer_Type" ); + ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); + ptr__Class_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyClass_Type" ); + ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); + ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); + ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); + ptr__File_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFile_Type" ); + ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); + ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); + ptr__Instance_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInstance_Type" ); + ptr__Int_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInt_Type" ); + ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); + ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); + ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); + ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" ); + ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" ); + ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" ); + ptr__String_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyString_Type" ); + ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); + ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); + ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); + +#if PY_MAJOR_VERSION >= 2 + ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); +#endif + } + catch( GetAddressException &e ) + { + OutputDebugString( python_dll_name ); + OutputDebugString( " does not contain symbol "); + OutputDebugString( e.name ); + OutputDebugString( "\n" ); + + return false; + } + + return true; + } + +// +// Wrap variables as function calls +// +PyObject * _Exc_ArithmeticError() { return ptr__Exc_ArithmeticError; } +PyObject * _Exc_AssertionError() { return ptr__Exc_AssertionError; } +PyObject * _Exc_AttributeError() { return ptr__Exc_AttributeError; } +PyObject * _Exc_EnvironmentError() { return ptr__Exc_EnvironmentError; } +PyObject * _Exc_EOFError() { return ptr__Exc_EOFError; } +PyObject * _Exc_Exception() { return ptr__Exc_Exception; } +PyObject * _Exc_FloatingPointError() { return ptr__Exc_FloatingPointError; } +PyObject * _Exc_ImportError() { return ptr__Exc_ImportError; } +PyObject * _Exc_IndexError() { return ptr__Exc_IndexError; } +PyObject * _Exc_IOError() { return ptr__Exc_IOError; } +PyObject * _Exc_KeyboardInterrupt() { return ptr__Exc_KeyboardInterrupt; } +PyObject * _Exc_KeyError() { return ptr__Exc_KeyError; } +PyObject * _Exc_LookupError() { return ptr__Exc_LookupError; } +PyObject * _Exc_MemoryError() { return ptr__Exc_MemoryError; } +PyObject * _Exc_MemoryErrorInst() { return ptr__Exc_MemoryErrorInst; } +PyObject * _Exc_NameError() { return ptr__Exc_NameError; } +PyObject * _Exc_NotImplementedError() { return ptr__Exc_NotImplementedError; } +PyObject * _Exc_OSError() { return ptr__Exc_OSError; } +PyObject * _Exc_OverflowError() { return ptr__Exc_OverflowError; } +PyObject * _Exc_RuntimeError() { return ptr__Exc_RuntimeError; } +PyObject * _Exc_StandardError() { return ptr__Exc_StandardError; } +PyObject * _Exc_SyntaxError() { return ptr__Exc_SyntaxError; } +PyObject * _Exc_SystemError() { return ptr__Exc_SystemError; } +PyObject * _Exc_SystemExit() { return ptr__Exc_SystemExit; } +PyObject * _Exc_TypeError() { return ptr__Exc_TypeError; } +PyObject * _Exc_ValueError() { return ptr__Exc_ValueError; } +#ifdef MS_WINDOWS +PyObject * _Exc_WindowsError() { return ptr__Exc_WindowsError; } +#endif +PyObject * _Exc_ZeroDivisionError() { return ptr__Exc_ZeroDivisionError; } + +#if PY_MAJOR_VERSION >= 2 +PyObject * _Exc_IndentationError() { return ptr__Exc_IndentationError; } +PyObject * _Exc_TabError() { return ptr__Exc_TabError; } +PyObject * _Exc_UnboundLocalError() { return ptr__Exc_UnboundLocalError; } +PyObject * _Exc_UnicodeError() { return ptr__Exc_UnicodeError; } +#endif + +// +// wrap items in Object.h +// +PyObject * _None() { return ptr__PyNone; } + + +PyTypeObject * _Buffer_Type() { return ptr__Buffer_Type; } +PyTypeObject * _CFunction_Type() { return ptr__CFunction_Type; } +PyTypeObject * _Class_Type() { return ptr__Class_Type; } +PyTypeObject * _CObject_Type() { return ptr__CObject_Type; } +PyTypeObject * _Complex_Type() { return ptr__Complex_Type; } +PyTypeObject * _Dict_Type() { return ptr__Dict_Type; } +PyTypeObject * _File_Type() { return ptr__File_Type; } +PyTypeObject * _Float_Type() { return ptr__Float_Type; } +PyTypeObject * _Function_Type() { return ptr__Function_Type; } +PyTypeObject * _Instance_Type() { return ptr__Instance_Type; } +PyTypeObject * _Int_Type() { return ptr__Int_Type; } +PyTypeObject * _List_Type() { return ptr__List_Type; } +PyTypeObject * _Long_Type() { return ptr__Long_Type; } +PyTypeObject * _Method_Type() { return ptr__Method_Type; } +PyTypeObject * _Module_Type() { return ptr__Module_Type; } +PyTypeObject * _Range_Type() { return ptr__Range_Type; } +PyTypeObject * _Slice_Type() { return ptr__Slice_Type; } +PyTypeObject * _String_Type() { return ptr__String_Type; } +PyTypeObject * _TraceBack_Type() { return ptr__TraceBack_Type; } +PyTypeObject * _Tuple_Type() { return ptr__Tuple_Type; } +PyTypeObject * _Type_Type() { return ptr__Type_Type; } + +#if PY_MAJOR_VERSION >= 2 +PyTypeObject * _Unicode_Type() { return ptr__Unicode_Type; } +#endif + +char *__Py_PackageContext() { return *ptr__Py_PackageContext; } + + +// +// wrap the Python Flag variables +// +int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; } +int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; } +int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; } +int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; } +int &_Py_TabcheckFlag() { return *ptr_Py_TabcheckFlag; } +int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; } +#if PY_MAJOR_VERSION >= 2 +int &_Py_UnicodeFlag() { return *ptr_Py_UnicodeFlag; } +#endif + +void _XINCREF( PyObject *op ) + { + // This function must match the contents of Py_XINCREF(op) + if( op == NULL ) + return; + +#ifdef Py_REF_DEBUG + (*ptr_Py_RefTotal)++; +#endif + (op)->ob_refcnt++; + + } + +void _XDECREF( PyObject *op ) + { + // This function must match the contents of Py_XDECREF(op); + if( op == NULL ) + return; + +#ifdef Py_REF_DEBUG + (*ptr_Py_RefTotal)--; +#endif + + if (--(op)->ob_refcnt == 0) + _Py_Dealloc((PyObject *)(op)); + } + + +#else +#error "Can only delay load under Win32" +#endif + +#else + +// +// Duplicated these declarations from rangeobject.h which is missing the +// extern "C". This has been reported as a bug upto and include 2.1 +// +extern "C" DL_IMPORT(PyTypeObject) PyRange_Type; +extern "C" DL_IMPORT(PyObject *) PyRange_New(long, long, long, int); + + +//================================================================================ +// +// Map onto Macros +// +//================================================================================ + +// +// Wrap variables as function calls +// + +PyObject * _Exc_ArithmeticError() { return ::PyExc_ArithmeticError; } +PyObject * _Exc_AssertionError() { return ::PyExc_AssertionError; } +PyObject * _Exc_AttributeError() { return ::PyExc_AttributeError; } +PyObject * _Exc_EnvironmentError() { return ::PyExc_EnvironmentError; } +PyObject * _Exc_EOFError() { return ::PyExc_EOFError; } +PyObject * _Exc_Exception() { return ::PyExc_Exception; } +PyObject * _Exc_FloatingPointError() { return ::PyExc_FloatingPointError; } +PyObject * _Exc_ImportError() { return ::PyExc_ImportError; } +PyObject * _Exc_IndexError() { return ::PyExc_IndexError; } +PyObject * _Exc_IOError() { return ::PyExc_IOError; } +PyObject * _Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; } +PyObject * _Exc_KeyError() { return ::PyExc_KeyError; } +PyObject * _Exc_LookupError() { return ::PyExc_LookupError; } +PyObject * _Exc_MemoryError() { return ::PyExc_MemoryError; } +PyObject * _Exc_MemoryErrorInst() { return ::PyExc_MemoryErrorInst; } +PyObject * _Exc_NameError() { return ::PyExc_NameError; } +PyObject * _Exc_NotImplementedError() { return ::PyExc_NotImplementedError; } +PyObject * _Exc_OSError() { return ::PyExc_OSError; } +PyObject * _Exc_OverflowError() { return ::PyExc_OverflowError; } +PyObject * _Exc_RuntimeError() { return ::PyExc_RuntimeError; } +PyObject * _Exc_StandardError() { return ::PyExc_StandardError; } +PyObject * _Exc_SyntaxError() { return ::PyExc_SyntaxError; } +PyObject * _Exc_SystemError() { return ::PyExc_SystemError; } +PyObject * _Exc_SystemExit() { return ::PyExc_SystemExit; } +PyObject * _Exc_TypeError() { return ::PyExc_TypeError; } +PyObject * _Exc_ValueError() { return ::PyExc_ValueError; } +PyObject * _Exc_ZeroDivisionError() { return ::PyExc_ZeroDivisionError; } + +#ifdef MS_WINDOWS +PyObject * _Exc_WindowsError() { return ::PyExc_WindowsError; } +#endif + + +#if PY_MAJOR_VERSION >= 2 +PyObject * _Exc_IndentationError() { return ::PyExc_IndentationError; } +PyObject * _Exc_TabError() { return ::PyExc_TabError; } +PyObject * _Exc_UnboundLocalError() { return ::PyExc_UnboundLocalError; } +PyObject * _Exc_UnicodeError() { return ::PyExc_UnicodeError; } +#endif + + +// +// wrap items in Object.h +// +PyObject * _None() { return &::_Py_NoneStruct; } + +PyTypeObject * _Buffer_Type() { return &PyBuffer_Type; } +PyTypeObject * _CFunction_Type() { return &PyCFunction_Type; } +PyTypeObject * _Class_Type() { return &PyClass_Type; } +PyTypeObject * _CObject_Type() { return &PyCObject_Type; } +PyTypeObject * _Complex_Type() { return &PyComplex_Type; } +PyTypeObject * _Dict_Type() { return &PyDict_Type; } +PyTypeObject * _File_Type() { return &PyFile_Type; } +PyTypeObject * _Float_Type() { return &PyFloat_Type; } +PyTypeObject * _Function_Type() { return &PyFunction_Type; } +PyTypeObject * _Instance_Type() { return &PyInstance_Type; } +PyTypeObject * _Int_Type() { return &PyInt_Type; } +PyTypeObject * _List_Type() { return &PyList_Type; } +PyTypeObject * _Long_Type() { return &PyLong_Type; } +PyTypeObject * _Method_Type() { return &PyMethod_Type; } +PyTypeObject * _Module_Type() { return &PyModule_Type; } +PyTypeObject * _Range_Type() { return &PyRange_Type; } +PyTypeObject * _Slice_Type() { return &PySlice_Type; } +PyTypeObject * _String_Type() { return &PyString_Type; } +PyTypeObject * _TraceBack_Type() { return &PyTraceBack_Type; } +PyTypeObject * _Tuple_Type() { return &PyTuple_Type; } +PyTypeObject * _Type_Type() { return &PyType_Type; } + +#if PY_MAJOR_VERSION >= 2 +PyTypeObject * _Unicode_Type() { return &PyUnicode_Type; } +#endif + +// +// wrap flags +// +int &_Py_DebugFlag() { return Py_DebugFlag; } +int &_Py_InteractiveFlag() { return Py_InteractiveFlag; } +int &_Py_OptimizeFlag() { return Py_OptimizeFlag; } +int &_Py_NoSiteFlag() { return Py_NoSiteFlag; } +int &_Py_TabcheckFlag() { return Py_TabcheckFlag; } +int &_Py_VerboseFlag() { return Py_VerboseFlag; } +#if PY_MAJOR_VERSION >= 2 +int &_Py_UnicodeFlag() { return Py_UnicodeFlag; } +#endif +char *__Py_PackageContext() { return _Py_PackageContext; } + +// +// Needed to keep the abstactions for delayload interface +// +void _XINCREF( PyObject *op ) + { + Py_XINCREF(op); + } + +void _XDECREF( PyObject *op ) + { + Py_XDECREF(op); + } + +#endif +} diff --git a/lib/kross/python/cxx/IndirectPythonInterface.hxx b/lib/kross/python/cxx/IndirectPythonInterface.hxx new file mode 100644 index 00000000..8f2d275d --- /dev/null +++ b/lib/kross/python/cxx/IndirectPythonInterface.hxx @@ -0,0 +1,156 @@ +#ifndef __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ +#define __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ + +#include <Python.h> + +namespace Py +{ +bool InitialisePythonIndirectInterface(); + +// +// Wrap Exception variables as function calls +// +PyObject * _Exc_Exception(); +PyObject * _Exc_StandardError(); +PyObject * _Exc_ArithmeticError(); +PyObject * _Exc_LookupError(); + +PyObject * _Exc_AssertionError(); +PyObject * _Exc_AttributeError(); +PyObject * _Exc_EOFError(); +PyObject * _Exc_FloatingPointError(); +PyObject * _Exc_EnvironmentError(); +PyObject * _Exc_IOError(); +PyObject * _Exc_OSError(); +PyObject * _Exc_ImportError(); +PyObject * _Exc_IndexError(); +PyObject * _Exc_KeyError(); +PyObject * _Exc_KeyboardInterrupt(); +PyObject * _Exc_MemoryError(); +PyObject * _Exc_NameError(); +PyObject * _Exc_OverflowError(); +PyObject * _Exc_RuntimeError(); +PyObject * _Exc_NotImplementedError(); +PyObject * _Exc_SyntaxError(); +PyObject * _Exc_SystemError(); +PyObject * _Exc_SystemExit(); +PyObject * _Exc_TypeError(); +PyObject * _Exc_ValueError(); +PyObject * _Exc_ZeroDivisionError(); +#ifdef MS_WINDOWS +PyObject * _Exc_WindowsError(); +#endif + +PyObject * _Exc_MemoryErrorInst(); + +#if PY_MAJOR_VERSION >= 2 +PyObject * _Exc_IndentationError(); +PyObject * _Exc_TabError(); +PyObject * _Exc_UnboundLocalError(); +PyObject * _Exc_UnicodeError(); +#endif + +// +// Wrap Object variables as function calls +// +PyObject * _None(); + + +// +// Wrap Type variables as function calls +// +PyTypeObject * _List_Type(); +bool _List_Check( PyObject *o ); + +PyTypeObject * _Buffer_Type(); +bool _Buffer_Check( PyObject *op ); + +PyTypeObject * _Class_Type(); +bool _Class_Check( PyObject *op ); + +PyTypeObject * _Instance_Type(); +bool _Instance_Check( PyObject *op ); + +PyTypeObject * _Method_Type(); +bool _Method_Check( PyObject *op ); + +PyTypeObject * _CObject_Type(); +bool _CObject_Check( PyObject *op ); + +PyTypeObject * _Complex_Type(); +bool _Complex_Check( PyObject *op ); + +PyTypeObject * _Dict_Type(); +bool _Dict_Check( PyObject *op ); + +PyTypeObject * _File_Type(); +bool _File_Check( PyObject *op ); + +PyTypeObject * _Float_Type(); +bool _Float_Check( PyObject *op ); + +PyTypeObject * _Frame_Type(); +bool _Frame_Check( PyObject *op ); + +PyTypeObject * _Function_Type(); +bool _Function_Check( PyObject *op ); + +PyTypeObject * _Int_Type(); +bool _Int_Check( PyObject *op ); + +PyTypeObject * _List_Type(); +bool _List_Check( PyObject *op ); + +PyTypeObject * _Long_Type(); +bool _Long_Check( PyObject *op ); + +PyTypeObject * _CFunction_Type(); +bool _CFunction_Check( PyObject *op ); + +PyTypeObject * _Module_Type(); +bool _Module_Check( PyObject *op ); + +PyTypeObject * _Type_Type(); +bool _Type_Check( PyObject *op ); + +PyTypeObject * _Range_Type(); +bool _Range_Check( PyObject *op ); + +PyTypeObject * _Slice_Type(); +bool _Slice_Check( PyObject *op ); + +PyTypeObject * _String_Type(); +bool _String_Check( PyObject *op ); + +PyTypeObject * _Unicode_Type(); +bool _Unicode_Check( PyObject *op ); + +PyTypeObject * _TraceBack_Type(); +bool _TraceBack_Check( PyObject *v ); + +PyTypeObject * _Tuple_Type(); +bool _Tuple_Check( PyObject *op ); + +#if PY_MAJOR_VERSION >= 2 +PyTypeObject * _Unicode_Type(); +bool _Unicode_Check( PyObject *op ); +#endif + +int &_Py_DebugFlag(); +int &_Py_InteractiveFlag(); +int &_Py_OptimizeFlag(); +int &_Py_NoSiteFlag(); +int &_Py_TabcheckFlag(); +int &_Py_VerboseFlag(); + +#if PY_MAJOR_VERSION >= 2 +int &_Py_UnicodeFlag(); +#endif + +void _XINCREF( PyObject *op ); +void _XDECREF( PyObject *op ); + +char *__Py_PackageContext(); +} + +#endif // __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ diff --git a/lib/kross/python/cxx/Legal.html b/lib/kross/python/cxx/Legal.html new file mode 100755 index 00000000..cf6a530f --- /dev/null +++ b/lib/kross/python/cxx/Legal.html @@ -0,0 +1,40 @@ +<html> + +<head> +<title>Legal Notice</title> +<meta name="GENERATOR" content="Microsoft FrontPage 3.0"> +</head> + +<body> + +<h1>Legal Notice</h1> + +<p>*** Legal Notice for all LLNL-contributed files *** </p> + +<p>Copyright (c) 1996. The Regents of the University of California. All rights reserved. </p> + +<p>Permission to use, copy, modify, and distribute this software for any purpose without +fee is hereby granted, provided that this entire notice is included in all copies of any +software which is or includes a copy or modification of this software and in all copies of +the supporting documentation for such software. </p> + +<p>This work was produced at the University of California, Lawrence Livermore National +Laboratory under contract no. W-7405-ENG-48 between the U.S. Department of Energy and The +Regents of the University of California for the operation of UC LLNL. </p> + +<h2>DISCLAIMER </h2> + +<p>This software was prepared as an account of work sponsored by an agency of the United +States Government. Neither the United States Government nor the University of California +nor any of their employees, makes any warranty, express or implied, or assumes any +liability or responsibility for the accuracy, completeness, or usefulness of any +information, apparatus, product, or process disclosed, or represents that its use would +not infringe privately-owned rights. Reference herein to any specific commercial products, +process, or service by trade name, trademark, manufacturer, or otherwise, does not +necessarily constitute or imply its endorsement, recommendation, or favoring by the United +States Government or the University of California. The views and opinions of authors +expressed herein do not necessarily state or reflect those of the United States Government +or the University of California, and shall not be used for advertising or product +endorsement purposes.</p> +</body> +</html> diff --git a/lib/kross/python/cxx/Makefile.am b/lib/kross/python/cxx/Makefile.am new file mode 100644 index 00000000..d1c72c87 --- /dev/null +++ b/lib/kross/python/cxx/Makefile.am @@ -0,0 +1,19 @@ +include $(top_srcdir)/lib/kross/Makefile.global + +noinst_LTLIBRARIES = libkrosspythoncxx.la + +libkrosspythoncxx_la_SOURCES = \ + cxxsupport.cxx \ + cxx_extensions.cxx \ + cxxextensions.c \ + IndirectPythonInterface.cxx + +libkrosspythoncxx_la_LDFLAGS = $(LIBPYTHON) $(all_libraries) -Wnounresolved + +METASOURCES = AUTO +INCLUDES = $(KROSS_INCLUDES) $(PYTHONINC) $(all_includes) +SUBDIRS = . + +clean: + @rm -f *.o 2> /dev/null + @rm -f $(BIN) 2> /dev/null diff --git a/lib/kross/python/cxx/Objects.hxx b/lib/kross/python/cxx/Objects.hxx new file mode 100644 index 00000000..41648320 --- /dev/null +++ b/lib/kross/python/cxx/Objects.hxx @@ -0,0 +1,2804 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 1998 The Regents of the University of California. +// All rights reserved. See LEGAL.LLNL for full text and disclaimer. +//---------------------------------------------------------------------------// + +#ifndef __CXX_Objects__h +#define __CXX_Objects__h + +// Prevent warnings +#if defined(_XOPEN_SOURCE) +#undef _XOPEN_SOURCE +#endif + +#include "Python.h" +#include "Config.hxx" +#include "Exception.hxx" + + +#include <iostream> +#include STR_STREAM +#include <string> +#include <iterator> +#include <utility> +#include <typeinfo> + +namespace Py + { + typedef int sequence_index_type; // type of an index into a sequence + + // Forward declarations + class Object; + class Type; + template<TEMPLATE_TYPENAME T> class SeqBase; + class String; + class List; + template<TEMPLATE_TYPENAME T> class MapBase; + + // new_reference_to also overloaded below on Object + inline PyObject* new_reference_to(PyObject* p) + { + Py::_XINCREF(p); + return p; + } + + // returning Null() from an extension method triggers a + // Python exception + inline PyObject* Null() + { + return (static_cast<PyObject*>(0)); + } + + //===========================================================================// + // class Object + // The purpose of this class is to serve as the most general kind of + // Python object, for the purpose of writing C++ extensions in Python + // Objects hold a PyObject* which they own. This pointer is always a + // valid pointer to a Python object. In children we must maintain this behavior. + // + // Instructions on how to make your own class MyType descended from Object: + // (0) Pick a base class, either Object or perhaps SeqBase<T> or MapBase<T>. + // This example assumes Object. + + // (1) Write a routine int MyType_Check (PyObject *) modeled after PyInt_Check, + // PyFloat_Check, etc. + + // (2) Add method accepts: + // virtual bool accepts (PyObject *pyob) const { + // return pyob && MyType_Check (pyob); + // } + + // (3) Include the following constructor and copy constructor + // + /* + explicit MyType (PyObject *pyob): Object(pyob) { + validate(); + } + + MyType(const Object& other): Object(other.ptr()) { + validate(); + } + */ + + // Alernate version for the constructor to allow for construction from owned pointers: + /* + explicit MyType (PyObject *pyob): Object(pyob) { + validate(); + } + */ + + // You may wish to add other constructors; see the classes below for examples. + // Each constructor must use "set" to set the pointer + // and end by validating the pointer you have created. + + // (4) Each class needs at least these two assignment operators: + /* + MyType& operator= (const Object& rhs) { + return (*this = *rhs); + } + + Mytype& operator= (PyObject* rhsp) { + if(ptr() == rhsp) return *this; + set(rhsp); + return *this; + } + */ + // Note on accepts: constructors call the base class + // version of a virtual when calling the base class constructor, + // so the test has to be done explicitly in a descendent. + + // If you are inheriting from PythonExtension<T> to define an object + // note that it contains PythonExtension<T>::check + // which you can use in accepts when writing a wrapper class. + // See Demo/range.h and Demo/range.cxx for an example. + + class Object + { + private: + // the pointer to the Python object + // Only Object sets this directly. + // The default constructor for Object sets it to Py_None and + // child classes must use "set" to set it + // + PyObject* p; + + protected: + + void set (PyObject* pyob, bool owned = false) + { + release(); + p = pyob; + if (!owned) + { + Py::_XINCREF (p); + } + validate(); + } + + void release () + { + Py::_XDECREF (p); + p = 0; + } + + void validate() + { + // release pointer if not the right type + if (! accepts (p)) + { + release (); + if(PyErr_Occurred()) + { // Error message already set + throw Exception(); + } + // Better error message if RTTI available +#if defined( _CPPRTTI ) + std::string s("Error creating object of type "); + s += (typeid (*this)).name(); + throw TypeError (s); +#else + throw TypeError ("CXX: type error."); +#endif + } + } + + public: + // Constructor acquires new ownership of pointer unless explicitly told not to. + explicit Object (PyObject* pyob=Py::_None(), bool owned = false): p (pyob) + { + if(!owned) + { + Py::_XINCREF (p); + } + validate(); + } + + // Copy constructor acquires new ownership of pointer + Object (const Object& ob): p(ob.p) + { + Py::_XINCREF (p); + validate(); + } + + // Assignment acquires new ownership of pointer + Object& operator= (const Object& rhs) + { + set(rhs.p); + return *this; + } + + Object& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + + // Destructor + virtual ~Object () + { + release (); + } + + // Loaning the pointer to others, retain ownership + PyObject* operator* () const + { + return p; + } + + // Explicit reference_counting changes + void increment_reference_count() + { + Py::_XINCREF(p); + } + + void decrement_reference_count() + { + // not allowed to commit suicide, however + if(reference_count() == 1) + throw RuntimeError("Object::decrement_reference_count error."); + Py::_XDECREF(p); + } + // Would like to call this pointer() but messes up STL in SeqBase<T> + PyObject* ptr () const + { + return p; + } + + // + // Queries + // + + // Can pyob be used in this object's constructor? + virtual bool accepts (PyObject *pyob) const + { + return (pyob != 0); + } + + int reference_count () const + { // the reference count + return p ? p->ob_refcnt : 0; + } + + Type type () const; // the type object associated with this one + + String str () const; // the str() representation + + std::string as_string() const; + + String repr () const; // the repr () representation + + List dir () const; // the dir() list + + bool hasAttr (const std::string& s) const + { + return PyObject_HasAttrString (p, const_cast<char*>(s.c_str())) ? true: false; + } + + Object getAttr (const std::string& s) const + { + return Object (PyObject_GetAttrString (p, const_cast<char*>(s.c_str())), true); + } + + Object getItem (const Object& key) const + { + return Object (PyObject_GetItem(p, *key), true); + } + + long hashValue () const + { + return PyObject_Hash (p); + } + + // + // int print (FILE* fp, int flags=Py_Print_RAW) + // { + // return PyObject_Print (p, fp, flags); + // } + // + bool is(PyObject *pother) const + { // identity test + return p == pother; + } + + bool is(const Object& other) const + { // identity test + return p == other.p; + } + + bool isCallable () const + { + return PyCallable_Check (p) != 0; + } + + bool isInstance () const + { + return PyInstance_Check (p) != 0; + } + + bool isDict () const + { + return Py::_Dict_Check (p); + } + + bool isList () const + { + return Py::_List_Check (p); + } + + bool isMapping () const + { + return PyMapping_Check (p) != 0; + } + + bool isNumeric () const + { + return PyNumber_Check (p) != 0; + } + + bool isSequence () const + { + return PySequence_Check (p) != 0; + } + + bool isTrue () const + { + return PyObject_IsTrue (p) != 0; + } + + bool isType (const Type& t) const; + + bool isTuple() const + { + return Py::_Tuple_Check(p); + } + + bool isString() const + { + return Py::_String_Check(p) || Py::_Unicode_Check(p); + } + + bool isUnicode() const + { + return Py::_Unicode_Check(p); + } + + // Commands + void setAttr (const std::string& s, const Object& value) + { + if(PyObject_SetAttrString (p, const_cast<char*>(s.c_str()), *value) == -1) + throw AttributeError ("getAttr failed."); + } + + void delAttr (const std::string& s) + { + if(PyObject_DelAttrString (p, const_cast<char*>(s.c_str())) == -1) + throw AttributeError ("delAttr failed."); + } + + // PyObject_SetItem is too weird to be using from C++ + // so it is intentionally omitted. + + void delItem (const Object& /*key*/) + { + //if(PyObject_DelItem(p, *key) == -1) + // failed to link on Windows? + throw KeyError("delItem failed."); + } + // Equality and comparison use PyObject_Compare + + bool operator==(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k == 0; + } + + bool operator!=(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k != 0; + + } + + bool operator>=(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k >= 0; + } + + bool operator<=(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k <= 0; + } + + bool operator<(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k < 0; + } + + bool operator>(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k > 0; + } + }; + // End of class Object + inline PyObject* new_reference_to(const Object& g) + { + PyObject* p = g.ptr(); + Py::_XINCREF(p); + return p; + } + + // Nothing() is what an extension method returns if + // there is no other return value. + inline Object Nothing() + { + return Object(Py::_None()); + } + + // Python special None value + inline Object None() + { + return Object(Py::_None()); + } + + // TMM: 31May'01 - Added the #ifndef so I can exlude iostreams. +#ifndef CXX_NO_IOSTREAMS + std::ostream& operator<< (std::ostream& os, const Object& ob); +#endif + + // Class Type + class Type: public Object + { + public: + explicit Type (PyObject* pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + Type (const Object& ob): Object(*ob) + { + validate(); + } + + Type(const Type& t): Object(t) + { + validate(); + } + + Type& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Type& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Type_Check (pyob); + } + }; + + + // + // Convert an owned Python pointer into a CXX Object + // + inline Object asObject (PyObject *p) + { + return Object(p, true); + } + + + + + // =============================================== + // class Int + class Int: public Object + { + public: + // Constructor + explicit Int (PyObject *pyob, bool owned = false): Object (pyob, owned) + { + validate(); + } + + Int (const Int& ob): Object(*ob) + { + validate(); + } + + // create from long + explicit Int (long v = 0L): Object(PyInt_FromLong(v), true) + { + validate(); + } + + // create from int + explicit Int (int v) + { + long w = v; + set(PyInt_FromLong(w), true); + validate(); + } + + Int (const Object& ob) + { + set(PyNumber_Int(*ob), true); + validate(); + } + + // Assignment acquires new ownership of pointer + + Int& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Int& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (PyNumber_Int(rhsp), true); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Int_Check (pyob); + } + // convert to long + operator long() const + { + return PyInt_AsLong (ptr()); + } + // assign from an int + Int& operator= (int v) + { + set (PyInt_FromLong (long(v)), true); + return *this; + } + // assign from long + Int& operator= (long v) + { + set (PyInt_FromLong (v), true); + return *this; + } + }; + + // =============================================== + // class Long + class Long: public Object + { + public: + // Constructor + explicit Long (PyObject *pyob, bool owned = false): Object (pyob, owned) + { + validate(); + } + + Long (const Long& ob): Object(ob.ptr()) + { + validate(); + } + + // create from long + explicit Long (long v = 0L) + : Object(PyLong_FromLong(v), true) + { + validate(); + } + // create from int + explicit Long (int v) + : Object(PyLong_FromLong(static_cast<long>(v)), true) + { + validate(); + } + + // create from unsigned long + explicit Long (unsigned long v) + : Object(PyLong_FromUnsignedLong(v), true) + { + validate(); + } + + // try to create from any object + Long (const Object& ob) + : Object(PyNumber_Long(*ob), true) + { + validate(); + } + + // Assignment acquires new ownership of pointer + + Long& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Long& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (PyNumber_Long(rhsp), true); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Long_Check (pyob); + } + // convert to long + operator long() const + { + return PyLong_AsLong (ptr()); + } + operator double() const + { + return PyLong_AsDouble (ptr()); + } + operator unsigned long() const + { + return PyLong_AsUnsignedLong (ptr()); + } + // assign from an int + Long& operator= (int v) + { + set(PyLong_FromLong (long(v)), true); + return *this; + } + // assign from long + Long& operator= (long v) + { + set(PyLong_FromLong (v), true); + return *this; + } + // assign from unsigned long + Long& operator= (unsigned long v) + { + set(PyLong_FromUnsignedLong (v), true); + return *this; + } + }; + + // =============================================== + // class Float + // + class Float: public Object + { + public: + // Constructor + explicit Float (PyObject *pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + Float (const Float& f): Object(f) + { + validate(); + } + + // make from double + explicit Float (double v=0.0) + : Object(PyFloat_FromDouble (v), true) + { + validate(); + } + + // try to make from any object + Float (const Object& ob) + : Object(PyNumber_Float(*ob), true) + { + validate(); + } + + Float& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Float& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (PyNumber_Float(rhsp), true); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Float_Check (pyob); + } + // convert to double + operator double () const + { + return PyFloat_AsDouble (ptr()); + } + // assign from a double + Float& operator= (double v) + { + set(PyFloat_FromDouble (v), true); + return *this; + } + // assign from an int + Float& operator= (int v) + { + set(PyFloat_FromDouble (double(v)), true); + return *this; + } + // assign from long + Float& operator= (long v) + { + set(PyFloat_FromDouble (double(v)), true); + return *this; + } + // assign from an Int + Float& operator= (const Int& iob) + { + set(PyFloat_FromDouble (double(long(iob))), true); + return *this; + } + }; + + // =============================================== + // class Complex + class Complex: public Object + { + public: + // Constructor + explicit Complex (PyObject *pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + Complex (const Complex& f): Object(f) + { + validate(); + } + + // make from double + explicit Complex (double v=0.0, double w=0.0) + :Object(PyComplex_FromDoubles (v, w), true) + { + validate(); + } + + Complex& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Complex& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Complex_Check (pyob); + } + // convert to Py_complex + operator Py_complex () const + { + return PyComplex_AsCComplex (ptr()); + } + // assign from a Py_complex + Complex& operator= (const Py_complex& v) + { + set(PyComplex_FromCComplex (v), true); + return *this; + } + // assign from a double + Complex& operator= (double v) + { + set(PyComplex_FromDoubles (v, 0.0), true); + return *this; + } + // assign from an int + Complex& operator= (int v) + { + set(PyComplex_FromDoubles (double(v), 0.0), true); + return *this; + } + // assign from long + Complex& operator= (long v) + { + set(PyComplex_FromDoubles (double(v), 0.0), true); + return *this; + } + // assign from an Int + Complex& operator= (const Int& iob) + { + set(PyComplex_FromDoubles (double(long(iob)), 0.0), true); + return *this; + } + + double real() const + { + return PyComplex_RealAsDouble(ptr()); + } + + double imag() const + { + return PyComplex_ImagAsDouble(ptr()); + } + }; + // Sequences + // Sequences are here represented as sequences of items of type T. + // The base class SeqBase<T> represents that. + // In basic Python T is always "Object". + + // seqref<T> is what you get if you get elements from a non-const SeqBase<T>. + // Note: seqref<T> could probably be a nested class in SeqBase<T> but that might stress + // some compilers needlessly. Simlarly for mapref later. + + // While this class is not intended for enduser use, it needs some public + // constructors for the benefit of the STL. + + // See Scott Meyer's More Essential C++ for a description of proxies. + // This application is even more complicated. We are doing an unusual thing + // in having a double proxy. If we want the STL to work + // properly we have to compromise by storing the rvalue inside. The + // entire Object API is repeated so that things like s[i].isList() will + // work properly. + + // Still, once in a while a weird compiler message may occur using expressions like x[i] + // Changing them to Object(x[i]) helps the compiler to understand that the + // conversion of a seqref to an Object is wanted. + + template<TEMPLATE_TYPENAME T> + class seqref + { + protected: + SeqBase<T>& s; // the sequence + int offset; // item number + T the_item; // lvalue + public: + + seqref (SeqBase<T>& seq, sequence_index_type j) + : s(seq), offset(j), the_item (s.getItem(j)) + {} + + seqref (const seqref<T>& range) + : s(range.s), offset(range.offset), the_item(range.the_item) + {} + + // TMM: added this seqref ctor for use with STL algorithms + seqref (Object& obj) + : s(dynamic_cast< SeqBase<T>&>(obj)) + , offset( NULL ) + , the_item(s.getItem(offset)) + {} + ~seqref() + {} + + operator T() const + { // rvalue + return the_item; + } + + seqref<T>& operator=(const seqref<T>& rhs) + { //used as lvalue + the_item = rhs.the_item; + s.setItem(offset, the_item); + return *this; + } + + seqref<T>& operator=(const T& ob) + { // used as lvalue + the_item = ob; + s.setItem(offset, ob); + return *this; + } + + // forward everything else to the item + PyObject* ptr () const + { + return the_item.ptr(); + } + + int reference_count () const + { // the reference count + return the_item.reference_count(); + } + + Type type () const + { + return the_item.type(); + } + + String str () const; + + String repr () const; + + bool hasAttr (const std::string& attr_name) const + { + return the_item.hasAttr(attr_name); + } + + Object getAttr (const std::string& attr_name) const + { + return the_item.getAttr(attr_name); + } + + Object getItem (const Object& key) const + { + return the_item.getItem(key); + } + + long hashValue () const + { + return the_item.hashValue(); + } + + bool isCallable () const + { + return the_item.isCallable(); + } + + bool isInstance () const + { + return the_item.isInstance(); + } + + bool isDict () const + { + return the_item.isDict(); + } + + bool isList () const + { + return the_item.isList(); + } + + bool isMapping () const + { + return the_item.isMapping(); + } + + bool isNumeric () const + { + return the_item.isNumeric(); + } + + bool isSequence () const + { + return the_item.isSequence(); + } + + bool isTrue () const + { + return the_item.isTrue(); + } + + bool isType (const Type& t) const + { + return the_item.isType (t); + } + + bool isTuple() const + { + return the_item.isTuple(); + } + + bool isString() const + { + return the_item.isString(); + } + // Commands + void setAttr (const std::string& attr_name, const Object& value) + { + the_item.setAttr(attr_name, value); + } + + void delAttr (const std::string& attr_name) + { + the_item.delAttr(attr_name); + } + + void delItem (const Object& key) + { + the_item.delItem(key); + } + + bool operator==(const Object& o2) const + { + return the_item == o2; + } + + bool operator!=(const Object& o2) const + { + return the_item != o2; + } + + bool operator>=(const Object& o2) const + { + return the_item >= o2; + } + + bool operator<=(const Object& o2) const + { + return the_item <= o2; + } + + bool operator<(const Object& o2) const + { + return the_item < o2; + } + + bool operator>(const Object& o2) const + { + return the_item > o2; + } + }; // end of seqref + + + // class SeqBase<T> + // ...the base class for all sequence types + + template<TEMPLATE_TYPENAME T> + class SeqBase: public Object + { + public: + // STL definitions + typedef size_t size_type; + typedef seqref<T> reference; + typedef T const_reference; + typedef seqref<T>* pointer; + typedef int difference_type; + typedef T value_type; // TMM: 26Jun'01 + + virtual size_type max_size() const + { + return std::string::npos; // ? + } + + virtual size_type capacity() const + { + return size(); + } + + virtual void swap(SeqBase<T>& c) + { + SeqBase<T> temp = c; + c = ptr(); + set(temp.ptr()); + } + + virtual size_type size () const + { + return PySequence_Length (ptr()); + } + + explicit SeqBase<T> () + :Object(PyTuple_New(0), true) + { + validate(); + } + + explicit SeqBase<T> (PyObject* pyob, bool owned=false) + : Object(pyob, owned) + { + validate(); + } + + SeqBase<T> (const Object& ob): Object(ob) + { + validate(); + } + + // Assignment acquires new ownership of pointer + + SeqBase<T>& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + SeqBase<T>& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + + virtual bool accepts (PyObject *pyob) const + { + return pyob && PySequence_Check (pyob); + } + + size_type length () const + { + return PySequence_Length (ptr()); + } + + // Element access + const T operator[](sequence_index_type index) const + { + return getItem(index); + } + + seqref<T> operator[](sequence_index_type index) + { + return seqref<T>(*this, index); + } + + virtual T getItem (sequence_index_type i) const + { + return T(asObject(PySequence_GetItem (ptr(), i))); + } + + virtual void setItem (sequence_index_type i, const T& ob) + { + if (PySequence_SetItem (ptr(), i, *ob) == -1) + { + throw Exception(); + } + } + + SeqBase<T> repeat (int count) const + { + return SeqBase<T> (PySequence_Repeat (ptr(), count), true); + } + + SeqBase<T> concat (const SeqBase<T>& other) const + { + return SeqBase<T> (PySequence_Concat(ptr(), *other), true); + } + + // more STL compatability + const T front () const + { + return getItem(0); + } + + seqref<T> front() + { + return seqref<T>(this, 0); + } + + const T back () const + { + return getItem(size()-1); + } + + seqref<T> back() + { + return seqref<T>(this, size()-1); + } + + void verify_length(size_type required_size) const + { + if (size() != required_size) + throw IndexError ("Unexpected SeqBase<T> length."); + } + + void verify_length(size_type min_size, size_type max_size) const + { + size_type n = size(); + if (n < min_size || n > max_size) + throw IndexError ("Unexpected SeqBase<T> length."); + } + + class iterator + : public random_access_iterator_parent(seqref<T>) + { + protected: + friend class SeqBase<T>; + SeqBase<T>* seq; + int count; + + public: + ~iterator () + {} + + iterator () + : seq( 0 ) + , count( 0 ) + {} + + iterator (SeqBase<T>* s, int where) + : seq( s ) + , count( where ) + {} + + iterator (const iterator& other) + : seq( other.seq ) + , count( other.count ) + {} + + bool eql (const iterator& other) const + { + return (*seq == *other.seq) && (count == other.count); + } + + bool neq (const iterator& other) const + { + return (*seq != *other.seq) || (count != other.count); + } + + bool lss (const iterator& other) const + { + return (count < other.count); + } + + bool gtr (const iterator& other) const + { + return (count > other.count); + } + + bool leq (const iterator& other) const + { + return (count <= other.count); + } + + bool geq (const iterator& other) const + { + return (count >= other.count); + } + + seqref<T> operator*() + { + return seqref<T>(*seq, count); + } + + seqref<T> operator[] (sequence_index_type i) + { + return seqref<T>(*seq, count + i); + } + + iterator& operator=(const iterator& other) + { + if (this == &other) return *this; + seq = other.seq; + count = other.count; + return *this; + } + + iterator operator+(int n) const + { + return iterator(seq, count + n); + } + + iterator operator-(int n) const + { + return iterator(seq, count - n); + } + + iterator& operator+=(int n) + { + count = count + n; + return *this; + } + + iterator& operator-=(int n) + { + count = count - n; + return *this; + } + + int operator-(const iterator& other) const + { + if (*seq != *other.seq) + throw RuntimeError ("SeqBase<T>::iterator comparison error"); + return count - other.count; + } + + // prefix ++ + iterator& operator++ () + { count++; return *this;} + // postfix ++ + iterator operator++ (int) + { return iterator(seq, count++);} + // prefix -- + iterator& operator-- () + { count--; return *this;} + // postfix -- + iterator operator-- (int) + { return iterator(seq, count--);} + + std::string diagnose() const + { + std::OSTRSTREAM oss; + oss << "iterator diagnosis " << seq << ", " << count << std::ends; + return std::string(oss.str()); + } + }; // end of class SeqBase<T>::iterator + + iterator begin () + { + return iterator(this, 0); + } + + iterator end () + { + return iterator(this, length()); + } + + class const_iterator + : public random_access_iterator_parent(const Object) + { + protected: + friend class SeqBase<T>; + const SeqBase<T>* seq; + sequence_index_type count; + + public: + ~const_iterator () + {} + + const_iterator () + : seq( 0 ) + , count( 0 ) + {} + + const_iterator (const SeqBase<T>* s, int where) + : seq( s ) + , count( where ) + {} + + const_iterator(const const_iterator& other) + : seq( other.seq ) + , count( other.count ) + {} + + const T operator*() const + { + return seq->getItem(count); + } + + const T operator[] (sequence_index_type i) const + { + return seq->getItem(count + i); + } + + const_iterator& operator=(const const_iterator& other) + { + if (this == &other) return *this; + seq = other.seq; + count = other.count; + return *this; + } + + const_iterator operator+(int n) const + { + return const_iterator(seq, count + n); + } + + bool eql (const const_iterator& other) const + { + return (*seq == *other.seq) && (count == other.count); + } + + bool neq (const const_iterator& other) const + { + return (*seq != *other.seq) || (count != other.count); + } + + bool lss (const const_iterator& other) const + { + return (count < other.count); + } + + bool gtr (const const_iterator& other) const + { + return (count > other.count); + } + + bool leq (const const_iterator& other) const + { + return (count <= other.count); + } + + bool geq (const const_iterator& other) const + { + return (count >= other.count); + } + + const_iterator operator-(int n) + { + return const_iterator(seq, count - n); + } + + const_iterator& operator+=(int n) + { + count = count + n; + return *this; + } + + const_iterator& operator-=(int n) + { + count = count - n; + return *this; + } + + int operator-(const const_iterator& other) const + { + if (*seq != *other.seq) + throw RuntimeError ("SeqBase<T>::const_iterator::- error"); + return count - other.count; + } + // prefix ++ + const_iterator& operator++ () + { count++; return *this;} + // postfix ++ + const_iterator operator++ (int) + { return const_iterator(seq, count++);} + // prefix -- + const_iterator& operator-- () + { count--; return *this;} + // postfix -- + const_iterator operator-- (int) + { return const_iterator(seq, count--);} + }; // end of class SeqBase<T>::const_iterator + + const_iterator begin () const + { + return const_iterator(this, 0); + } + + const_iterator end () const + { + return const_iterator(this, length()); + } + }; + + // Here's an important typedef you might miss if reading too fast... + typedef SeqBase<Object> Sequence; + + template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right); + template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right); + template <TEMPLATE_TYPENAME T> bool operator< (const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right); + template <TEMPLATE_TYPENAME T> bool operator> (const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right); + template <TEMPLATE_TYPENAME T> bool operator<=(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right); + template <TEMPLATE_TYPENAME T> bool operator>=(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right); + + template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right); + template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right); + template <TEMPLATE_TYPENAME T> bool operator< (const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right); + template <TEMPLATE_TYPENAME T> bool operator> (const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right); + template <TEMPLATE_TYPENAME T> bool operator<=(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right); + template <TEMPLATE_TYPENAME T> bool operator>=(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right); + + + extern bool operator==(const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator< (const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator> (const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator<=(const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator>=(const Sequence::iterator& left, const Sequence::iterator& right); + + extern bool operator==(const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator!=(const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator< (const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator> (const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator<=(const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator>=(const Sequence::const_iterator& left, const Sequence::const_iterator& right); + + // ================================================== + // class Char + // Python strings return strings as individual elements. + // I'll try having a class Char which is a String of length 1 + // + typedef std::basic_string<Py_UNICODE> unicodestring; + extern Py_UNICODE unicode_null_string[1]; + + class Char: public Object + { + public: + explicit Char (PyObject *pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + Char (const Object& ob): Object(ob) + { + validate(); + } + + Char (const std::string& v = "") + :Object(PyString_FromStringAndSize (const_cast<char*>(v.c_str()),1), true) + { + validate(); + } + + Char (char v) + : Object(PyString_FromStringAndSize (&v, 1), true) + { + validate(); + } + + Char (Py_UNICODE v) + : Object(PyUnicode_FromUnicode (&v, 1), true) + { + validate(); + } + // Assignment acquires new ownership of pointer + Char& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Char& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob)) && PySequence_Length (pyob) == 1; + } + + // Assignment from C string + Char& operator= (const std::string& v) + { + set(PyString_FromStringAndSize (const_cast<char*>(v.c_str()),1), true); + return *this; + } + + Char& operator= (char v) + { + set(PyString_FromStringAndSize (&v, 1), true); + return *this; + } + + Char& operator= (const unicodestring& v) + { + set(PyUnicode_FromUnicode (const_cast<Py_UNICODE*>(v.data()),1), true); + return *this; + } + + Char& operator= (Py_UNICODE v) + { + set(PyUnicode_FromUnicode (&v, 1), true); + return *this; + } + + // Conversion + operator String() const; + + operator std::string () const + { + return std::string(PyString_AsString (ptr())); + } + }; + + class String: public SeqBase<Char> + { + public: + virtual size_type capacity() const + { + return max_size(); + } + + explicit String (PyObject *pyob, bool owned = false): SeqBase<Char>(pyob, owned) + { + validate(); + } + + String (const Object& ob): SeqBase<Char>(ob) + { + validate(); + } + + String() + : SeqBase<Char>( PyString_FromStringAndSize( "", 0 ), true ) + { + validate(); + } + + String( const std::string& v ) + : SeqBase<Char>( PyString_FromStringAndSize( const_cast<char*>(v.data()), + static_cast<int>( v.length() ) ), true ) + { + validate(); + } + + String( const char *s, const char *encoding, const char *error="strict" ) + : SeqBase<Char>( PyUnicode_Decode( s, strlen( s ), encoding, error ), true ) + { + validate(); + } + + String( const char *s, int len, const char *encoding, const char *error="strict" ) + : SeqBase<Char>( PyUnicode_Decode( s, len, encoding, error ), true ) + { + validate(); + } + + String( const std::string &s, const char *encoding, const char *error="strict" ) + : SeqBase<Char>( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true ) + { + validate(); + } + + String( const std::string& v, std::string::size_type vsize ) + : SeqBase<Char>(PyString_FromStringAndSize( const_cast<char*>(v.data()), + static_cast<int>( vsize ) ), true) + { + validate(); + } + + String( const char *v, int vsize ) + : SeqBase<Char>(PyString_FromStringAndSize( const_cast<char*>(v), vsize ), true ) + { + validate(); + } + + String( const char* v ) + : SeqBase<Char>( PyString_FromString( v ), true ) + { + validate(); + } + + // Assignment acquires new ownership of pointer + String& operator= ( const Object& rhs ) + { + return *this = *rhs; + } + + String& operator= (PyObject* rhsp) + { + if( ptr() == rhsp ) + return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob)); + } + + // Assignment from C string + String& operator= (const std::string& v) + { + set( PyString_FromStringAndSize( const_cast<char*>( v.data() ), + static_cast<int>( v.length() ) ), true ); + return *this; + } + String& operator= (const unicodestring& v) + { + set( PyUnicode_FromUnicode( const_cast<Py_UNICODE*>( v.data() ), + static_cast<int>( v.length() ) ), true ); + return *this; + } + + + // Encode + String encode( const char *encoding, const char *error="strict" ) + { + if( isUnicode() ) + { + return String( PyUnicode_AsEncodedString( ptr(), encoding, error ) ); + } + else + { + return String( PyString_AsEncodedObject( ptr(), encoding, error ) ); + } + } + + String decode( const char *encoding, const char *error="strict" ) + { + return Object( PyString_AsDecodedObject( ptr(), encoding, error ) ); + } + + // Queries + virtual size_type size () const + { + if( isUnicode() ) + { + return static_cast<size_type>( PyUnicode_GET_SIZE (ptr()) ); + } + else + { + return static_cast<size_type>( PyString_Size (ptr()) ); + } + } + + operator std::string () const + { + return as_std_string(); + } + + std::string as_std_string() const + { + if( isUnicode() ) + { + throw TypeError("cannot return std::string from Unicode object"); + } + else + { + return std::string( PyString_AsString( ptr() ), static_cast<size_type>( PyString_Size( ptr() ) ) ); + } + } + + unicodestring as_unicodestring() const + { + if( isUnicode() ) + { + return unicodestring( PyUnicode_AS_UNICODE( ptr() ), + static_cast<size_type>( PyUnicode_GET_SIZE( ptr() ) ) ); + } + else + { + throw TypeError("can only return unicodestring from Unicode object"); + } + } + }; + + // ================================================== + // class Tuple + class Tuple: public Sequence + { + public: + virtual void setItem (sequence_index_type offset, const Object&ob) + { + // note PyTuple_SetItem is a thief... + if(PyTuple_SetItem (ptr(), offset, new_reference_to(ob)) == -1) + { + throw Exception(); + } + } + + // Constructor + explicit Tuple (PyObject *pyob, bool owned = false): Sequence (pyob, owned) + { + validate(); + } + + Tuple (const Object& ob): Sequence(ob) + { + validate(); + } + + // New tuple of a given size + explicit Tuple (int size = 0) + { + set(PyTuple_New (size), true); + validate (); + for (sequence_index_type i=0; i < size; i++) + { + if(PyTuple_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1) + { + throw Exception(); + } + } + } + // Tuple from any sequence + explicit Tuple (const Sequence& s) + { + sequence_index_type limit( sequence_index_type( s.length() ) ); + + set(PyTuple_New (limit), true); + validate(); + + for(sequence_index_type i=0; i < limit; i++) + { + if(PyTuple_SetItem (ptr(), i, new_reference_to(s[i])) == -1) + { + throw Exception(); + } + } + } + // Assignment acquires new ownership of pointer + + Tuple& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Tuple& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Tuple_Check (pyob); + } + + Tuple getSlice (int i, int j) const + { + return Tuple (PySequence_GetSlice (ptr(), i, j), true); + } + + }; + + // ================================================== + // class List + + class List: public Sequence + { + public: + // Constructor + explicit List (PyObject *pyob, bool owned = false): Sequence(pyob, owned) + { + validate(); + } + List (const Object& ob): Sequence(ob) + { + validate(); + } + // Creation at a fixed size + List (int size = 0) + { + set(PyList_New (size), true); + validate(); + for (sequence_index_type i=0; i < size; i++) + { + if(PyList_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1) + { + throw Exception(); + } + } + } + + // List from a sequence + List (const Sequence& s): Sequence() + { + int n = s.length(); + set(PyList_New (n), true); + validate(); + for (sequence_index_type i=0; i < n; i++) + { + if(PyList_SetItem (ptr(), i, new_reference_to(s[i])) == -1) + { + throw Exception(); + } + } + } + + virtual size_type capacity() const + { + return max_size(); + } + // Assignment acquires new ownership of pointer + + List& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + List& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_List_Check (pyob); + } + + List getSlice (int i, int j) const + { + return List (PyList_GetSlice (ptr(), i, j), true); + } + + void setSlice (int i, int j, const Object& v) + { + if(PyList_SetSlice (ptr(), i, j, *v) == -1) + { + throw Exception(); + } + } + + void append (const Object& ob) + { + if(PyList_Append (ptr(), *ob) == -1) + { + throw Exception(); + } + } + + void insert (int i, const Object& ob) + { + if(PyList_Insert (ptr(), i, *ob) == -1) + { + throw Exception(); + } + } + + void sort () + { + if(PyList_Sort(ptr()) == -1) + { + throw Exception(); + } + } + + void reverse () + { + if(PyList_Reverse(ptr()) == -1) + { + throw Exception(); + } + } + }; + + + // Mappings + // ================================================== + template<TEMPLATE_TYPENAME T> + class mapref + { + protected: + MapBase<T>& s; // the map + Object key; // item key + T the_item; + + public: + mapref<T> (MapBase<T>& map, const std::string& k) + : s(map), the_item() + { + key = String(k); + if(map.hasKey(key)) the_item = map.getItem(key); + }; + + mapref<T> (MapBase<T>& map, const Object& k) + : s(map), key(k), the_item() + { + if(map.hasKey(key)) the_item = map.getItem(key); + }; + + ~mapref() + {} + + // MapBase<T> stuff + // lvalue + mapref<T>& operator=(const mapref<T>& other) + { + if(this == &other) return *this; + the_item = other.the_item; + s.setItem(key, other.the_item); + return *this; + }; + + mapref<T>& operator= (const T& ob) + { + the_item = ob; + s.setItem (key, ob); + return *this; + } + + // rvalue + operator T() const + { + return the_item; + } + + // forward everything else to the_item + PyObject* ptr () const + { + return the_item.ptr(); + } + + int reference_count () const + { // the mapref count + return the_item.reference_count(); + } + + Type type () const + { + return the_item.type(); + } + + String str () const + { + return the_item.str(); + } + + String repr () const + { + return the_item.repr(); + } + + bool hasAttr (const std::string& attr_name) const + { + return the_item.hasAttr(attr_name); + } + + Object getAttr (const std::string& attr_name) const + { + return the_item.getAttr(attr_name); + } + + Object getItem (const Object& k) const + { + return the_item.getItem(k); + } + + long hashValue () const + { + return the_item.hashValue(); + } + + bool isCallable () const + { + return the_item.isCallable(); + } + + bool isList () const + { + return the_item.isList(); + } + + bool isMapping () const + { + return the_item.isMapping(); + } + + bool isNumeric () const + { + return the_item.isNumeric(); + } + + bool isSequence () const + { + return the_item.isSequence(); + } + + bool isTrue () const + { + return the_item.isTrue(); + } + + bool isType (const Type& t) const + { + return the_item.isType (t); + } + + bool isTuple() const + { + return the_item.isTuple(); + } + + bool isString() const + { + return the_item.isString(); + } + + // Commands + void setAttr (const std::string& attr_name, const Object& value) + { + the_item.setAttr(attr_name, value); + } + + void delAttr (const std::string& attr_name) + { + the_item.delAttr(attr_name); + } + + void delItem (const Object& k) + { + the_item.delItem(k); + } + }; // end of mapref + + // TMM: now for mapref<T> + template< class T > + bool operator==(const mapref<T>& left, const mapref<T>& right) + { + return true; // NOT completed. + } + + template< class T > + bool operator!=(const mapref<T>& left, const mapref<T>& right) + { + return true; // not completed. + } + + template<TEMPLATE_TYPENAME T> + class MapBase: public Object + { + protected: + explicit MapBase<T>() + {} + public: + // reference: proxy class for implementing [] + // TMM: 26Jun'01 - the types + // If you assume that Python mapping is a hash_map... + // hash_map::value_type is not assignable, but + // (*it).second = data must be a valid expression + typedef size_t size_type; + typedef Object key_type; + typedef mapref<T> data_type; + typedef std::pair< const T, T > value_type; + typedef std::pair< const T, mapref<T> > reference; + typedef const std::pair< const T, const T > const_reference; + typedef std::pair< const T, mapref<T> > pointer; + + // Constructor + explicit MapBase<T> (PyObject *pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + // TMM: 02Jul'01 - changed MapBase<T> to Object in next line + MapBase<T> (const Object& ob): Object(ob) + { + validate(); + } + + // Assignment acquires new ownership of pointer + MapBase<T>& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + MapBase<T>& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && PyMapping_Check(pyob); + } + + // Clear -- PyMapping Clear is missing + // + + void clear () + { + List k = keys(); + for(List::iterator i = k.begin(); i != k.end(); i++) + { + delItem(*i); + } + } + + virtual size_type size() const + { + return PyMapping_Length (ptr()); + } + + // Element Access + T operator[](const std::string& key) const + { + return getItem(key); + } + + T operator[](const Object& key) const + { + return getItem(key); + } + + mapref<T> operator[](const std::string& key) + { + return mapref<T>(*this, key); + } + + mapref<T> operator[](const Object& key) + { + return mapref<T>(*this, key); + } + + int length () const + { + return PyMapping_Length (ptr()); + } + + bool hasKey (const std::string& s) const + { + return PyMapping_HasKeyString (ptr(),const_cast<char*>(s.c_str())) != 0; + } + + bool hasKey (const Object& s) const + { + return PyMapping_HasKey (ptr(), s.ptr()) != 0; + } + + T getItem (const std::string& s) const + { + return T( + asObject(PyMapping_GetItemString (ptr(),const_cast<char*>(s.c_str()))) + ); + } + + T getItem (const Object& s) const + { + return T( + asObject(PyObject_GetItem (ptr(), s.ptr())) + ); + } + + virtual void setItem (const char *s, const Object& ob) + { + if (PyMapping_SetItemString (ptr(), const_cast<char*>(s), *ob) == -1) + { + throw Exception(); + } + } + + virtual void setItem (const std::string& s, const Object& ob) + { + if (PyMapping_SetItemString (ptr(), const_cast<char*>(s.c_str()), *ob) == -1) + { + throw Exception(); + } + } + + virtual void setItem (const Object& s, const Object& ob) + { + if (PyObject_SetItem (ptr(), s.ptr(), ob.ptr()) == -1) + { + throw Exception(); + } + } + + void delItem (const std::string& s) + { + if (PyMapping_DelItemString (ptr(), const_cast<char*>(s.c_str())) == -1) + { + throw Exception(); + } + } + + void delItem (const Object& s) + { + if (PyMapping_DelItem (ptr(), *s) == -1) + { + throw Exception(); + } + } + // Queries + List keys () const + { + return List(PyMapping_Keys(ptr()), true); + } + + List values () const + { // each returned item is a (key, value) pair + return List(PyMapping_Values(ptr()), true); + } + + List items () const + { + return List(PyMapping_Items(ptr()), true); + } + + // iterators for MapBase<T> + // Added by TMM: 2Jul'01 - NOT COMPLETED + // There is still a bug. I decided to stop, before fixing the bug, because + // this can't be halfway efficient until Python gets built-in iterators. + // My current soln is to iterate over the map by getting a copy of its keys + // and iterating over that. Not a good solution. + + // The iterator holds a MapBase<T>* rather than a MapBase<T> because that's + // how the sequence iterator is implemented and it works. But it does seem + // odd to me - we are iterating over the map object, not the reference. + +#if 0 // here is the test code with which I found the (still existing) bug + typedef cxx::Dict d_t; + d_t d; + cxx::String s1("blah"); + cxx::String s2("gorf"); + d[ "one" ] = s1; + d[ "two" ] = s1; + d[ "three" ] = s2; + d[ "four" ] = s2; + + d_t::iterator it; + it = d.begin(); // this (using the assignment operator) is causing + // a problem; if I just use the copy ctor it works fine. + for( ; it != d.end(); ++it ) + { + d_t::value_type vt( *it ); + cxx::String rs = vt.second.repr(); + std::string ls = rs.operator std::string(); + fprintf( stderr, "%s\n", ls ); + } +#endif // 0 + + class iterator + { + // : public forward_iterator_parent( std::pair<const T,T> ) { + protected: + typedef std::forward_iterator_tag iterator_category; + typedef std::pair< const T, T > value_type; + typedef int difference_type; + typedef std::pair< const T, mapref<T> > pointer; + typedef std::pair< const T, mapref<T> > reference; + + friend class MapBase<T>; + // + MapBase<T>* map; + List keys; // for iterating over the map + List::iterator pos; // index into the keys + + public: + ~iterator () + {} + + iterator () + : map( 0 ) + , keys() + , pos() + {} + + iterator (MapBase<T>* m, bool end = false ) + : map( m ) + , keys( m->keys() ) + , pos( end ? keys.end() : keys.begin() ) + {} + + iterator (const iterator& other) + : map( other.map ) + , keys( other.keys ) + , pos( other.pos ) + {} + + reference operator*() + { + Object key = *pos; + return std::make_pair(key, mapref<T>(*map,key)); + } + + iterator& operator=(const iterator& other) + { + if (this == &other) + return *this; + map = other.map; + keys = other.keys; + pos = other.pos; + return *this; + } + + bool eql(const iterator& right) const + { + return *map == *right.map && pos == right.pos; + } + bool neq( const iterator& right ) const + { + return *map != *right.map || pos != right.pos; + } + + // pointer operator->() { + // return ; + // } + + // prefix ++ + iterator& operator++ () + { pos++; return *this;} + // postfix ++ + iterator operator++ (int) + { return iterator(map, keys, pos++);} + // prefix -- + iterator& operator-- () + { pos--; return *this;} + // postfix -- + iterator operator-- (int) + { return iterator(map, keys, pos--);} + + std::string diagnose() const + { + std::OSTRSTREAM oss; + oss << "iterator diagnosis " << map << ", " << pos << std::ends; + return std::string(oss.str()); + } + }; // end of class MapBase<T>::iterator + + iterator begin () + { + return iterator(this); + } + + iterator end () + { + return iterator(this, true); + } + + class const_iterator + { + protected: + typedef std::forward_iterator_tag iterator_category; + typedef const std::pair< const T, T > value_type; + typedef int difference_type; + typedef const std::pair< const T, T > pointer; + typedef const std::pair< const T, T > reference; + + friend class MapBase<T>; + const MapBase<T>* map; + List keys; // for iterating over the map + List::iterator pos; // index into the keys + + public: + ~const_iterator () + {} + + const_iterator () + : map( 0 ) + , keys() + , pos() + {} + + const_iterator (const MapBase<T>* m, List k, List::iterator p ) + : map( m ) + , keys( k ) + , pos( p ) + {} + + const_iterator(const const_iterator& other) + : map( other.map ) + , keys( other.keys ) + , pos( other.pos ) + {} + + bool eql(const const_iterator& right) const + { + return *map == *right.map && pos == right.pos; + } + bool neq( const const_iterator& right ) const + { + return *map != *right.map || pos != right.pos; + } + + + // const_reference operator*() { + // Object key = *pos; + // return std::make_pair( key, map->[key] ); + // GCC < 3 barfes on this line at the '['. + // } + + const_iterator& operator=(const const_iterator& other) + { + if (this == &other) return *this; + map = other.map; + keys = other.keys; + pos = other.pos; + return *this; + } + + // prefix ++ + const_iterator& operator++ () + { pos++; return *this;} + // postfix ++ + const_iterator operator++ (int) + { return const_iterator(map, keys, pos++);} + // prefix -- + const_iterator& operator-- () + { pos--; return *this;} + // postfix -- + const_iterator operator-- (int) + { return const_iterator(map, keys, pos--);} + }; // end of class MapBase<T>::const_iterator + + const_iterator begin () const + { + return const_iterator(this, 0); + } + + const_iterator end () const + { + return const_iterator(this, length()); + } + + }; // end of MapBase<T> + + typedef MapBase<Object> Mapping; + + template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME MapBase<T>::iterator& left, const EXPLICIT_TYPENAME MapBase<T>::iterator& right); + template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME MapBase<T>::iterator& left, const EXPLICIT_TYPENAME MapBase<T>::iterator& right); + template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME MapBase<T>::const_iterator& left, const EXPLICIT_TYPENAME MapBase<T>::const_iterator& right); + template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME MapBase<T>::const_iterator& left, const EXPLICIT_TYPENAME MapBase<T>::const_iterator& right); + + extern bool operator==(const Mapping::iterator& left, const Mapping::iterator& right); + extern bool operator!=(const Mapping::iterator& left, const Mapping::iterator& right); + extern bool operator==(const Mapping::const_iterator& left, const Mapping::const_iterator& right); + extern bool operator!=(const Mapping::const_iterator& left, const Mapping::const_iterator& right); + + + // ================================================== + // class Dict + class Dict: public Mapping + { + public: + // Constructor + explicit Dict (PyObject *pyob, bool owned=false): Mapping (pyob, owned) + { + validate(); + } + Dict (const Dict& ob): Mapping(ob) + { + validate(); + } + // Creation + Dict () + { + set(PyDict_New (), true); + validate(); + } + // Assignment acquires new ownership of pointer + + Dict& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Dict& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set(rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Dict_Check (pyob); + } + }; + + class Callable: public Object + { + protected: + explicit Callable (): Object() + {} + public: + // Constructor + explicit Callable (PyObject *pyob, bool owned = false): Object (pyob, owned) + { + validate(); + } + + Callable (const Object& ob): Object(ob) + { + validate(); + } + + // Assignment acquires new ownership of pointer + + Callable& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Callable& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && PyCallable_Check (pyob); + } + + // Call + Object apply(const Tuple& args) const + { + return asObject(PyObject_CallObject(ptr(), args.ptr())); + } + + // Call with keywords + Object apply(const Tuple& args, const Dict& kw) const + { + return asObject( PyEval_CallObjectWithKeywords( ptr(), args.ptr(), kw.ptr() ) ); + } + + Object apply(PyObject* pargs = 0) const + { + return apply (Tuple(pargs)); + } + }; + + class Module: public Object + { + public: + explicit Module (PyObject* pyob, bool owned = false): Object (pyob, owned) + { + validate(); + } + + // Construct from module name + explicit Module (const std::string&s): Object() + { + PyObject *m = PyImport_AddModule( const_cast<char *>(s.c_str()) ); + set( m, false ); + validate (); + } + + // Copy constructor acquires new ownership of pointer + Module (const Module& ob): Object(*ob) + { + validate(); + } + + Module& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Module& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set(rhsp); + return *this; + } + + Dict getDict() + { + return Dict(PyModule_GetDict(ptr())); + // Caution -- PyModule_GetDict returns borrowed reference! + } + }; + + // Numeric interface + inline Object operator+ (const Object& a) + { + return asObject(PyNumber_Positive(*a)); + } + inline Object operator- (const Object& a) + { + return asObject(PyNumber_Negative(*a)); + } + + inline Object abs(const Object& a) + { + return asObject(PyNumber_Absolute(*a)); + } + + inline std::pair<Object,Object> coerce(const Object& a, const Object& b) + { + PyObject *p1, *p2; + p1 = *a; + p2 = *b; + if(PyNumber_Coerce(&p1,&p2) == -1) + { + throw Exception(); + } + return std::pair<Object,Object>(asObject(p1), asObject(p2)); + } + + inline Object operator+ (const Object& a, const Object& b) + { + return asObject(PyNumber_Add(*a, *b)); + } + inline Object operator+ (const Object& a, int j) + { + return asObject(PyNumber_Add(*a, *Int(j))); + } + inline Object operator+ (const Object& a, double v) + { + return asObject(PyNumber_Add(*a, *Float(v))); + } + inline Object operator+ (int j, const Object& b) + { + return asObject(PyNumber_Add(*Int(j), *b)); + } + inline Object operator+ (double v, const Object& b) + { + return asObject(PyNumber_Add(*Float(v), *b)); + } + + inline Object operator- (const Object& a, const Object& b) + { + return asObject(PyNumber_Subtract(*a, *b)); + } + inline Object operator- (const Object& a, int j) + { + return asObject(PyNumber_Subtract(*a, *Int(j))); + } + inline Object operator- (const Object& a, double v) + { + return asObject(PyNumber_Subtract(*a, *Float(v))); + } + inline Object operator- (int j, const Object& b) + { + return asObject(PyNumber_Subtract(*Int(j), *b)); + } + inline Object operator- (double v, const Object& b) + { + return asObject(PyNumber_Subtract(*Float(v), *b)); + } + + inline Object operator* (const Object& a, const Object& b) + { + return asObject(PyNumber_Multiply(*a, *b)); + } + inline Object operator* (const Object& a, int j) + { + return asObject(PyNumber_Multiply(*a, *Int(j))); + } + inline Object operator* (const Object& a, double v) + { + return asObject(PyNumber_Multiply(*a, *Float(v))); + } + inline Object operator* (int j, const Object& b) + { + return asObject(PyNumber_Multiply(*Int(j), *b)); + } + inline Object operator* (double v, const Object& b) + { + return asObject(PyNumber_Multiply(*Float(v), *b)); + } + + inline Object operator/ (const Object& a, const Object& b) + { + return asObject(PyNumber_Divide(*a, *b)); + } + inline Object operator/ (const Object& a, int j) + { + return asObject(PyNumber_Divide(*a, *Int(j))); + } + inline Object operator/ (const Object& a, double v) + { + return asObject(PyNumber_Divide(*a, *Float(v))); + } + inline Object operator/ (int j, const Object& b) + { + return asObject(PyNumber_Divide(*Int(j), *b)); + } + inline Object operator/ (double v, const Object& b) + { + return asObject(PyNumber_Divide(*Float(v), *b)); + } + + inline Object operator% (const Object& a, const Object& b) + { + return asObject(PyNumber_Remainder(*a, *b)); + } + inline Object operator% (const Object& a, int j) + { + return asObject(PyNumber_Remainder(*a, *Int(j))); + } + inline Object operator% (const Object& a, double v) + { + return asObject(PyNumber_Remainder(*a, *Float(v))); + } + inline Object operator% (int j, const Object& b) + { + return asObject(PyNumber_Remainder(*Int(j), *b)); + } + inline Object operator% (double v, const Object& b) + { + return asObject(PyNumber_Remainder(*Float(v), *b)); + } + + inline Object type(const Exception&) // return the type of the error + { + PyObject *ptype, *pvalue, *ptrace; + PyErr_Fetch(&ptype, &pvalue, &ptrace); + Object result(ptype); + PyErr_Restore(ptype, pvalue, ptrace); + return result; + } + + inline Object value(const Exception&) // return the value of the error + { + PyObject *ptype, *pvalue, *ptrace; + PyErr_Fetch(&ptype, &pvalue, &ptrace); + Object result; + if(pvalue) result = pvalue; + PyErr_Restore(ptype, pvalue, ptrace); + return result; + } + + inline Object trace(const Exception&) // return the traceback of the error + { + PyObject *ptype, *pvalue, *ptrace; + PyErr_Fetch(&ptype, &pvalue, &ptrace); + Object result; + if(ptrace) result = ptrace; + PyErr_Restore(ptype, pvalue, ptrace); + return result; + } + + + +template<TEMPLATE_TYPENAME T> +String seqref<T>::str () const + { + return the_item.str(); + } + +template<TEMPLATE_TYPENAME T> +String seqref<T>::repr () const + { + return the_item.repr(); + } + + + } // namespace Py +#endif // __CXX_Objects__h diff --git a/lib/kross/python/cxx/PyCXX.html b/lib/kross/python/cxx/PyCXX.html new file mode 100644 index 00000000..566974c1 --- /dev/null +++ b/lib/kross/python/cxx/PyCXX.html @@ -0,0 +1,2131 @@ +<html> + +<head> +<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252"> +<title>Writing Python Extensions in C++</title> +<style> +H1, H2, H3, H4 {color: #000099; + background-color: lightskyblue} +h3 {position: relative; left: 20px} + +p {position: relative; left: 20px; margin-right: 20px} +pre {color: #0000cc; background-color: #eeeeee; position: relative; left: 40px; margin-right: 80px; + border-style: solid; border-color: black; border-width: thin} +kbd {color: #990000} +p cite, ol cite, ul cite {font-family: monospace; font-style: normal; font-size: normal} +li var, pre var, p var, kbd var {color: #009900; font-style: italic} +li samp, pre samp, p samp, kbd samp {color: #009900; font-weight: bold} +li p {position: relative; left: 0} +table { position: relative; left: 20px; border: solid #888888 1px; background-color: #eeeeee} +table th {border: solid #888888 1px; background-color: #88dd88; color: black} +table td {border: solid #888888 1px} +table td.code {border: solid #888888 1px;font-family: monospace; font-style: normal; font-size: normal} +p.param {background-color: #eeeeee; border-top: lightskyblue solid 4} +</style> + +</head> + +<body bgcolor="#FFFFFF"> + +<h1 ALIGN="center">Writing Python Extensions in C++</h1> + +<p ALIGN="CENTER">Barry Scott<br> +Reading, Berkshire, England<br> +<a href="mailto:[email protected]">[email protected]</a><br> +</p> + +<p ALIGN="CENTER">Paul F. Dubois, <a href="mailto:[email protected]">[email protected]</a><br> +Lawrence Livermore National Laboratory<br> +Livermore, California, U.S.A.</p> + + +<p>PyCXX is designed to make it easier to extend Python with C++</p> + + +<p>PyCXX is a set of C++ facilities to make it easier to write Python extensions. +The chief way in which PyCXX makes it easier to write Python extensions is that it greatly +increases the probability that your program will not make a reference-counting error and +will not have to continually check error returns from the Python C API. PyCXX +integrates Python with C++ in these ways: </p> + +<ul> + <li>C++ exception handling is relied on to detect errors and clean up. In a complicated + function this is often a tremendous problem when writing in C. With PyCXX, we let the + compiler keep track of what objects need to be dereferenced when an error occurs. + <li>The Standard Template Library (STL) and its many algorithms plug and play with Python + containers such as lists and tuples. + <li>The optional CXX_Extensions facility allows you to replace the clumsy C tables with + objects and method calls that define your modules and extension objects. +</ul> + +<h3>Download and Installation</h3> + +<p>Download PyCXX from <a href="http://sourceforge.net/projects/cxx/">http://sourceforge.net/projects/cxx/</a>.</p> + +<p>The distribution layout is:</p> +<table> +<tr><th>Directory</th><th>Description</th></tr> +<tr><td class=code>.</td><td>Makefile for Unix and Windows, Release documentation</td> +<tr><td class=code>./CXX</td><td>Header files</td> +<tr><td class=code>./Src</td><td>Source files</td> +<tr><td class=code>./Doc</td><td>Documentation</td> +<tr><td class=code>./Demo</td><td>Testing and Demonstartion files</td> +</table> + +<p>To use PyCXX you use its include files and add its source routines to your module.</p> + +<p>Installation:</p> +<ul> +<li>Install the PyCXX files into a directory of your choice. For example:<br> +Windows: <cite>C:\PyCXX</cite><br> +Unix: <cite>/usr/local/PyCXX</cite> +<li>Tell your compiler where the PyCXX header files are:<br> +Windows: <cite>cl /I=C:\PyCXX ...</cite><br> +Unix: <cite>g++ -I/usr/local/PyCXX ...</cite> +<li>Include PyCXX headers files in your code using the CXX prefix:<br> +<cite>#include "CXX/Object.hxx"</cite> +</ul> + +<p>The header file CXX/config.h may need to be adjusted for the +compiler you use. As of this writing, only a fairly obscure reference to part of the +standard library needs this adjustment. Unlike prior releases, PyCXX now assumes namespace +support and a standard C++ library. </p> + +<h3>Use of namespaces</h3> + +<p>All PyCXX assets are in namespace "Py". You need to include +the Py:: prefix when referring to them, or include the statement:</p> + +<p>using namespace Py;</p> + +<h2>Wrappers for standard objects: CXX_Objects.h</h2> + +<p>Header file CXX_Objects.h requires adding file Src/cxxsupport.cxx to +your module sources. CXX_Objects provides a set of wrapper classes that allow you access +to most of the Python C API using a C++ notation that closely resembles Python. For +example, this Python:</p> + +<pre>d = {} +d["a"] = 1 +d["b"] = 2 +alist = d.keys() +print alist</pre> + +<p>Can be written in C++:</p> + +<pre>Dict d; +List alist; +d["a"] = Int(1); +d["b"] = Int(2); +alist = d.keys(); +std::cout << alist << std::endl; +</pre> + +<p>You can optionally use the CXX/Extensions.hxx facility described later +to define Python extension modules and extension objects.</p> + +<h3>We avoid programming with Python object pointers</h3> + +<p>The essential idea is that we avoid, as much as possible, programming with pointers to +Python objects, that is, variables of type <cite>PyObject*</cite>. Instead, +we use instances of a family of C++ classes that represent the +usual Python objects. This family is easily extendible to include new kinds of Python +objects.</p> + +<p>For example, consider the case in which we wish to write a method, taking a single +integer argument, that will create a Python <cite>dict</cite> + and insert into it that the integer plus one under the key <cite>value</cite>. + In C we might do that as follows:</p> + +<pre>static PyObject* mymodule_addvalue (PyObject* self, PyObject* args) + { + PyObject *d; + PyObject* f; + int k; + PyArgs_ParseTuple(args, "i", &k); + d = PyDict_New(); + if (!d) + return NULL; + + f = PyInt_NEW(k+1); + if(!f) + { + Py_DECREF(d); /* have to get rid of d first */ + return NULL; + } + if(PyDict_SetItemString(d, "value", f) == -1) + { + Py_DECREF(f); + Py_DECREF(d); + return NULL; + } + + return d; + }</pre> + +<p>If you have written a significant Python extension, this tedium looks all too familiar. +The vast bulk of the coding is error checking and cleanup. Now compare the same thing +written in C++ using CXX/Objects.hxx. The things with Python-like names (Int, Dict, Tuple) are +from CXX/Objects.hxx.</p> + +<pre>static PyObject* mymodule_addvalue (PyObject* self, PyObject* pargs) + { + try { + Tuple args(pargs); + args.verify_length(1); + + Dict d; + Int k = args[0]; + d["value"] = k + 1; + + return new_reference_to(d); + } + catch (const PyException&) + { + return NULL; + } + }</pre> + +<p>If there are not the right number of arguments or the argument is not an +integer, an exception is thrown. In this case we choose to catch it and convert it into a +Python exception. The C++ exception handling mechanism takes care all the cleanup.</p> + +<p>Note that the creation of the <cite>Int k</cite> got the first argument <em>and</em> verified +that it is an <cite>Int</cite>.</p> + +<p>Just to peek ahead, if you wrote this method in an +ExtensionModule-derived module of your own, it would be a method and it could be written +even more simply:</p> + +<pre> +Object addvalue (Object & self, const Tuple & args) + { + args.verify_length(1); + Dict d; + Int k = args[0]; + d["value"] = k + 1; + return d; + } +</pre> + +<h2>The basic concept is to wrap Python pointers</h2> + + +<p>The basic concept of CXX/Objects.hxx is to create a wrapper around +each <cite>PyObject *</cite> so that the reference counting can be +done automatically, thus eliminating the most frequent source of errors. In addition, we +can then add methods and operators so that Python objects can be manipulated in C++ +much like you would in Python.</p> + +<p>Each <cite>Object</cite> contains a <cite>PyObject *</cite> +to which it owns a reference. When an <cite>Object</cite> is destroyed, it releases its ownership on +the pointer. Since C++ calls the destructors on objects that are about to go out of scope, +we are guaranteed that we will keep the reference counts right even if we unexpectedly +leave a routine with an exception.</p> + +<p>As a matter of philosophy, CXX/Objects.hxx prevents the creation of instances of its +classes unless the instance will be a valid instance of its class. When an attempt is made +to create an object that will not be valid, an exception is thrown.</p> + +<p>Class <cite>Object</cite> represents the most general kind of Python object. The rest of the classes +that represent Python objects inherit from it.</p> + +<pre>Object + Type + Int + Float + Long + Complex + Char + Sequence -> SeqBase<T> + String + Tuple + List + Mapping -> MapBase<T> + Dict + Callable + Module</pre> + +<p>There are several constructors for each of these classes. For example, you can create +an <cite>Int</cite> from an integer as in</p> + +<pre>Int s(3)</pre> + +<p>However, you can also create an instance of one of these classes using any <cite>PyObject*</cite> or +another <cite>Object</cite>. If the corresponding Python object does not actually have the type +desired, an exception is thrown. This is accomplished as follows. Class <cite>Object</cite> defines a +virtual function <cite>accepts</cite>:</p> + +<pre>virtual bool accepts(PyObject* p)</pre> + +<p>The base class version of <cite>accepts</cite> returns true for any pointer p except 0. This means +we can create an Object using any <cite>PyObject *</cite>, or from any other +<cite>Object</cite>. However, if we attempt to create an <cite>Int</cite> from a <cite>PyObject *</cite>, +the overridding version +of <cite>accepts</cite> in class <cite>Int</cite> will only accept pointers that correspond to Python ints. +Therefore if we have a <cite>Tuple t</cite> and we wish to get the first element and be sure it is an +<cite>Int</cite>, we do</p> + +<pre>Int first_element = t[0]</pre> + +<p>This will not only accomplish the goal of extracting the first element of the <cite>Tuple t</cite>, +but it will ensure that the result is an <cite>Int</cite>. If not, an exception is thrown. The +exception mechanism is discussed later.</p> + +<h2>Class Object</h2> + +<p>Class <cite>Object</cite> serves as the base class for the other classes. Its default constructor +constructs a <cite>Py_None</cite>, the unique object of Python type <cite>None</cite>. The interface to <cite>Object</cite> +consists of a large number of methods corresponding to the operations that are defined for +every Python object. In each case, the methods throw an exception if anything goes +wrong.</p> + +<p>There is no method corresponding to <cite>PyObject_SetItem</cite> with an arbitrary Python object +as a key. Instead, create an instance of a more specific child of <cite>Object</cite> and use the +appropriate facilities.</p> + +<p>The comparison operators use the Python comparison function to compare values. The +method <cite>is</cite> is available to test for absolute identity.</p> + +<p>A conversion to standard library string type <cite>std::string</cite> is supplied using method +<cite>as_string</cite>. Stream output of PyCXX <cite>Object</cite> instances uses this conversion, +which in turn uses the Python object's str() representation.</p> + +<p>All the numeric operators are defined on all possible combinations of <cite>Object</cite>, +<cite>long</cite>, and <cite>double</cite>. These use the corresponding Python operators, +and should the operation fail for some reason, an exception is thrown.</p> + +<h3>Dealing with pointers returned by the Python C API</h3> + +<p>Often, <cite>PyObject *</cite> pointers are acquired from some function, +particularly functions in the Python C API. If you wish to make an object from the pointer +returned by such a function, you need to know if the function returns you an <i>owned</i> +or <i>unowned</i> reference. Unowned references are unusual but there are some cases where +unowned references are returned.</p> + +<p>Usually, <cite>Object</cite> and its children acquire a new reference when constructed from a +<cite>PyObject *</cite>. This is usually not the right behavior if the reference comes from one +of the Python C API calls.</p> + +<p>If p is an owned reference, you can add the boolean <cite>true</cite> as an extra +argument in the creation routine, <cite>Object(p, true)</cite>, or use the function <cite>asObject(p)</cite> which +returns an <cite>Object</cite> created using the owned reference. For example, the routine +<cite>PyString_FromString</cite> returns an owned reference to a Python string object. You could write:</p> + +<pre>Object w = asObject( PyString_FromString("my string") );</pre> + +<p>or using the constructor,</p> + +<pre>Object w( PyString_FromString("my string"), true );</pre> + +<p>In fact, you would never do this, since PyCXX has a class String and you can just say: </p> + +<pre>String w( "my string" );</pre> + +<p>Indeed, since most of the Python C API is similarly embodied in <cite>Object</cite> +and its descendents, you probably will not use asObject all that often.</p> +<h3>Table 1: Class Object</h3> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Returns</th> + <th>Name(signature)</th> + <th>Comment</th> + </tr> + <tr> + <td colspan="3"><p align="center"><strong>Basic Methods</strong></td> + </tr> + <tr> + <td class=code>explicit </td> + <td class=code>Object (PyObject* pyob=Py_None, bool owned=false) </td> + <td>Construct from pointer. </td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Object (const Object& ob)</td> + <td>Copycons; acquires an owned reference.</td> + </tr> + <tr> + <td class=code>Object&</td> + <td class=code>operator= (const Object& rhs) </td> + <td>Acquires an owned reference.</td> + </tr> + <tr> + <td class=code>Object&</td> + <td class=code>operator= (PyObject* rhsp) </td> + <td>Acquires an owned reference.</td> + </tr> + <tr> + <td class=code>virtual</td> + <td class=code>~Object () </td> + <td>Releases the reference.</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>increment_reference_count() </td> + <td>Explicitly increment the count</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>decrement_reference_count()</td> + <td>Explicitly decrement count but not to zero</td> + </tr> + <tr> + <td class=code>PyObject*</td> + <td class=code>operator* () const</td> + <td>Lends the pointer</td> + </tr> + <tr> + <td class=code>PyObject*</td> + <td class=code>ptr () const</td> + <td>Lends the pointer</td> + </tr> + <tr> + <td class=code>virtual bool</td> + <td class=code>accepts (PyObject *pyob) const</td> + <td>Would assignment of pyob to this object succeed?</td> + </tr> + <tr> + <td class=code>std::string</td> + <td class=code>as_string() const</td> + <td>str() representation</td> + </tr> + <tr> + <td colspan="3" align="center"><strong>Python API Interface</strong></td> + </tr> + <tr> + <td class=code>int</td> + <td class=code>reference_count () const </td> + <td>reference count</td> + </tr> + <tr> + <td class=code>Type</td> + <td class=code>type () const</td> + <td>associated type object</td> + </tr> + <tr> + <td class=code>String</td> + <td class=code>str () const</td> + <td>str() representation</td> + </tr> + <tr> + <td class=code>String</td> + <td class=code>repr () const</td> + <td>repr () representation</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>hasAttr (const std::string& s) const</td> + <td>hasattr(this, s)</td> + </tr> + <tr> + <td class=code>Object</td> + <td class=code>getAttr (const std::string& s) const</td> + <td>getattr(this, s)</td> + </tr> + <tr> + <td class=code>Object</td> + <td class=code>getItem (const Object& key) const</td> + <td>getitem(this, key)</td> + </tr> + <tr> + <td class=code>long</td> + <td class=code>hashValue () const</td> + <td>hash(this)</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>setAttr (const std::string& s,<br>const Object& value)</td> + <td>this.s = value</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>delAttr (const std::string& s) </td> + <td>del this.s</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>delItem (const Object& key) </td> + <td>del this[key]</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isCallable () const</td> + <td>does this have callable behavior?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isList () const</td> + <td>is this a Python list?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isMapping () const</td> + <td>does this have mapping behaviors?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isNumeric () const</td> + <td>does this have numeric behaviors?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isSequence () const </td> + <td>does this have sequence behaviors?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isTrue () const</td> + <td>is this true in the Python sense?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isType (const Type& t) const</td> + <td>is type(this) == t?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isTuple() const</td> + <td>is this a Python tuple?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isString() const</td> + <td>is this a Python string?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isUnicode() const</td> + <td>is this a Python Unicode string?</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>isDict() const</td> + <td>is this a Python dictionary?</td> + </tr> + <tr> + <td colspan="3" align="center"><strong>Comparison Operators</strong></td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>is(PyObject* pother) const</td> + <td>test for identity</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>is(const Object& other) const</td> + <td>test for identity</td> + </tr> + <tr> + <td class=code>bool </td> + <td class=code>operator==(const Object& o2) const</td> + <td>Comparisons use Python cmp</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>operator!=(const Object& o2) const</td> + <td>Comparisons use Python cmp</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>operator>=(const Object& o2) const</td> + <td>Comparisons use Python cmp</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>operator<=(const Object& o2) const </td> + <td>Comparisons use Python cmp</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>operator<(const Object& o2) const</td> + <td>Comparisons use Python cmp</td> + </tr> + <tr> + <td class=code>bool</td> + <td class=code>operator>(const Object& o2) const</td> + <td>Comparisons use Python cmp</td> + </tr> +</table> + +<h1>The Basic Types</h1> + +<p>Corresponding to each of the basic Python types is a class that inherits from Object. +Here are the interfaces for those types. Each of them inherits from Object and therefore +has all of the inherited methods listed for Object. Where a virtual function is overridden +in a class, the name is underlined. </p> + +<h2>Class Type</h2> + +<p>Class Type corresponds to Python type objects. There is no default constructor.</p> + +<h3>Table 2: class Type</h3> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Returns</th> + <th>Name and Signature</th> + <th>Comments</th> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Type (PyObject* pyob, bool owned = false)</td> + <td>Constructor</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Type (const Object& ob)</td> + <td>Constructor</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Type(const Type& t)</td> + <td>Copycons</td> + </tr> + <tr> + <td class=code>Type&</td> + <td class=code>operator= (const Object& rhs) </td> + <td>Assignment</td> + </tr> + <tr> + <td class=code>Type&</td> + <td class=code>operator= (PyObject* rhsp) </td> + <td>Assignment</td> + </tr> + <tr> + <td class=code>virtual bool</td> + <td class=code><u>accepts</u> (PyObject *pyob) const</td> + <td>Uses PyType_Check</td> + </tr> +</table> + +<h2>Class Int</h2> + +<p>Class Int, derived publically from Object, corresponds to Python ints. Note that the +latter correspond to C long ints. Class Int has an implicit user-defined conversion to +long int. All constructors, on the other hand, are explicit. The default constructor +creates a Python int zero.</p> + +<h3>Table 3: class Int</h3> + + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Returns</td> + <th>Name and Signature</td> + <th>Comments</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Int (PyObject *pyob, bool owned= false, bool owned = false)</td> + <td>Constructor</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Int (const Int& ob)</td> + <td>Constructor</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Int (long v = 0L)</td> + <td>Construct from long</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Int (int v)</td> + <td>Contruct from int</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Int (const Object& ob)</td> + <td>Copycons</td> + </tr> + <tr> + <td class=code>Int&</td> + <td class=code>operator= (const Object& rhs)</td> + <td>Assignment</td> + </tr> + <tr> + <td class=code>Int&</td> + <td class=code>operator= (PyObject* rhsp)</td> + <td>Assignment</td> + </tr> + <tr> + <td class=code>virtual bool </td> + <td class=code> (PyObject *pyob) const </td> + <td>Based on PyInt_Check</td> + </tr> + <tr> + <td class=code>long</td> + <td class=code>operator long() const </td> + <td><em>Implicit</em> conversion to long int</td> + </tr> + <tr> + <td class=code>Int&</td> + <td class=code>operator= (int v)</td> + <td>Assign from int</td> + </tr> + <tr> + <td class=code>Int&</td> + <td class=code>operator= (long v) </td> + <td>Assign from long</td> + </tr> +</table> + +<hr> + +<h2>Class Long</h2> + +<p>Class Long, derived publically from Object, corresponds to Python type long. In Python, +a long is an integer type of unlimited size, and is usually used for applications such as +cryptography, not as a normal integer. Implicit conversions to both double and long are +provided, although the latter may of course fail if the number is actually too big. All +constructors are explicit. The default constructor produces a Python long zero.</p> + +<h3>Table 4: Class Long</h3> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Returns</td> + <th>Name and Signature</td> + <th>Comments</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Long (PyObject *pyob</a>, bool owned = false)</td> + <td>Constructor</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Long (const Int& ob)</td> + <td>Constructor</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Long (long v = 0L)</td> + <td>Construct from long</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Long (int v)</td> + <td>Contruct from int</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Long (const Object& ob)</td> + <td>Copycons</td> + </tr> + <tr> + <td class=code>Long&</td> + <td class=code>operator= (const Object& rhs)</td> + <td>Assignment</td> + </tr> + <tr> + <td class=code>Long&</td> + <td class=code>operator= (PyObject* rhsp)</td> + <td>Assignment</td> + </tr> + <tr> + <td class=code>virtual bool</td> + <td class=code>(PyObject *pyob) const </td> + <td>Based on PyLong_Check</td> + </tr> + <tr> + <td class=code>double</td> + <td class=code>operator double() const </td> + <td><em>Implicit</em> conversion to double</td> + </tr> + <tr> + <td class=code>long</td> + <td class=code>operator long() const</td> + <td><em>Implicit</em> conversion to long</td> + </tr> + <tr> + <td class=code>Long&</td> + <td class=code>operator= (int v)</td> + <td>Assign from int</td> + </tr> + <tr> + <td class=code>Long&</td> + <td class=code>operator= (long v) </td> + <td>Assign from long</td> + </tr> +</table> + +<h2>Class Float</h2> + +<p>Class Float corresponds to Python floats, which in turn correspond to C double. The +default constructor produces the Python float 0.0. </p> + +<h3>Table 5: Class Float</h3> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Returns</td> + <th>Name and Signature</td> + <th>Comments</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Float (PyObject *pyob</a>, bool owned = false) + </td> + <td>Constructor</td> + </tr> + <tr> + <td class=code></td> + <td class=code>Float (const Float& f) </td> + <td>Construct from float</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Float (double v=0.0)</td> + <td>Construct from double</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Float (const Object& ob)</td> + <td>Copycons</td> + </tr> + <tr> + <td class=code>Float&</td> + <td class=code>operator= (const Object& rhs)</td> + <td>Assignment</td> + </tr> + <tr> + <td class=code>Float&</td> + <td class=code>operator= (PyObject* rhsp)</td> + <td>Assignment</td> + </tr> + <tr> + <td class=code>virtual bool </td> + <td class=code>accepts (PyObject *pyob) const</td> + <td>Based on PyFloat_Check</td> + </tr> + <tr> + <td class=code>double </td> + <td class=code>operator double () const</td> + <td><em>Implicit</em> conversion to double</td> + </tr> + <tr> + <td class=code>Float& </td> + <td class=code>operator= (double v)</td> + <td>Assign from double</td> + </tr> + <tr> + <td class=code>Float& </td> + <td class=code>operator= (int v)</td> + <td>Assign from int</td> + </tr> + <tr> + <td class=code>Float& </td> + <td class=code>operator= (long v)</td> + <td>Assign from long</td> + </tr> + <tr> + <td class=code>Float& </td> + <td class=code>operator= (const Int& iob)</td> + <td>Assign from Int</td> + </tr> +</table> + +<h1>Sequences</h1> + +<p>PyCXX implements a quite sophisticated wrapper class for Python sequences. While every +effort has been made to disguise the sophistication, it may pop up in the form of obscure +compiler error messages, so in this documentation we will first detail normal usage and +then discuss what is under the hood.</p> + +<p>The basic idea is that we would like the subscript operator [] to work properly, and to +be able to use STL-style iterators and STL algorithms across the elements of the sequence.</p> + +<p>Sequences are implemented in terms of a templated base class, SeqBase<T>. The +parameter T is the answer to the question, sequence of what? For Lists, for example, T is +Object, because the most specific thing we know about an element of a List is simply that +it is an Object. (Class List is defined below; it is a descendent of Object that holds a +pointer to a Python list). For strings, T is Char, which is a wrapper in turn of Python +strings whose length is one.</p> + +<p>For convenience, the word <strong>Sequence</strong> is a typedef of SeqBase<Object>.</p> + +<h2>General sequences</h2> + +<p>Suppose you are writing an extension module method that expects the first argument to +be any kind of Python sequence, and you wish to return the length of that sequence. You +might write:</p> + +<pre>static PyObject* +my_module_seqlen (PyObject *self, PyObject* args) { + try + { + Tuple t(args); // set up a Tuple pointing to the arguments. + if(t.length() != 1) + throw PyException("Incorrect number of arguments to seqlen."); + Sequence s = t[0]; // get argument and be sure it is a sequence + return new_reference_to(Int(s.length())); + } + catch(const PyException&) + { + return Py_Null; + } +}</pre> + +<p>As we will explain later, the try/catch structure converts any errors, such as the +first argument not being a sequence, into a Python exception.</p> + +<h3>Subscripting</h3> + +<p>When a sequence is subscripted, the value returned is a special kind of object which +serves as a proxy object. The general idea of proxy objects is discussed in Scott Meyers' +book, "More Effective C++". Proxy objects are necessary because when one +subscripts a sequence it is not clear whether the value is to be used or the location +assigned to. Our proxy object is even more complicated than normal because a sequence +reference such as s[i] is not a direct reference to the i'th object of s. </p> + +<p>In normal use, you are not supposed to notice this magic going on behind your back. You +write:</p> + +<pre>Object t; +Sequence s; +s[2] = t + s[1]</pre> + +<p>and here is what happens: s[1] returns a proxy object. Since there is no addition +operator in Object that takes a proxy as an argument, the compiler decides to invoke an +automatic conversion of the proxy to an Object, which returns the desired component of s. +The addition takes place, and then there is an assignment operator in the proxy class +created by the s[2], and that assignment operator stuffs the result into the 2 component +of s.</p> + +<p>It is possible to fool this mechanism and end up with a compiler failing to admit that +a s[i] is an Object. If that happens, you can work around it by writing Object(s[i]), +which makes the desired implicit conversion, explicit.</p> + +<h3>Iterators</h3> + +<p>Each sequence class provides the following interface. The class seqref<T> is the +proxy class. We omit the details of the iterator, const_iterator, and seqref<T> +here. See CXX_Objects.h if necessary. The purpose of most of this interface is to satisfy +requirements of the STL.</p> + +<h3>The SeqBase<T> Interface</h3> + +<p>SeqBase<T> inherits from Object.</p> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + </tr> + <tr> + <td class=code>typedef int </td> + <td class=code>size_type</td> + </tr> + <tr> + <td class=code>typedef seqref<T></td> + <td class=code>reference</td> + </tr> + <tr> + <td class=code>typedef T </td> + <td class=code>const_reference</td> + </tr> + <tr> + <td class=code>typedef seqref<T>*</td> + <td class=code>pointer</td> + </tr> + <tr> + <td class=code>typedef int </td> + <td class=code>difference_type</td> + </tr> + <tr> + <td class=code>virtual size_type</td> + <td class=code>max_size() const</td> + </tr> + <tr> + <td class=code>virtual size_type </td> + <td class=code>capacity() const;</td> + </tr> + <tr> + <td class=code>virtual void </td> + <td class=code>swap(SeqBase<T>& c);</td> + </tr> + <tr> + <td class=code>virtual size_type </td> + <td class=code>size () const;</td> + </tr> + <tr> + <td class=code>explicit </td> + <td class=code>SeqBase<T> ();</td> + </tr> + <tr> + <td class=code>explicit </td> + <td class=code>SeqBase<T> (PyObject* pyob, bool owned = false);</td> + </tr> + <tr> + <td class=code>explicit </td> + <td class=code>SeqBase<T> (const Object& ob);</td> + </tr> + <tr> + <td class=code>SeqBase<T>& </td> + <td class=code>operator= (const Object& rhs);</td> + </tr> + <tr> + <td class=code>SeqBase<T>& </td> + <td class=code>operator= (PyObject* rhsp);</td> + </tr> + <tr> + <td class=code>virtual bool </td> + <td class=code>accepts (PyObject *pyob) const;</td> + </tr> + <tr> + <td class=code>size_type </td> + <td class=code>length () const ;</td> + </tr> + <tr> + <td class=code>const T </td> + <td class=code>operator[](size_type index) const; </td> + </tr> + <tr> + <td class=code>seqref<T> </td> + <td class=code>operator[](size_type index); </td> + </tr> + <tr> + <td class=code>virtual T </td> + <td class=code>getItem (size_type i) const;</td> + </tr> + <tr> + <td class=code>virtual void </td> + <td class=code>setItem (size_type i, const T& ob);</td> + </tr> + <tr> + <td class=code>SeqBase<T> </td> + <td class=code>repeat (int count) const;</td> + </tr> + <tr> + <td class=code>SeqBase<T> </td> + <td class=code>concat (const SeqBase<T>& other) const ;</td> + </tr> + <tr> + <td class=code>const T </td> + <td class=code>front () const;</td> + </tr> + <tr> + <td class=code>seqref<T> </td> + <td class=code>front();</td> + </tr> + <tr> + <td class=code>const T </td> + <td class=code>back () const;</td> + </tr> + <tr> + <td class=code>seqref<T> </td> + <td class=code>back(); </td> + </tr> + <tr> + <td class=code>void </td> + <td class=code>verify_length(size_type required_size);</td> + </tr> + <tr> + <td class=code>void </td> + <td class=code>verify_length(size_type min_size, size_type max_size);</td> + </tr> + <tr> + <td class=code>class</td> + <td class=code>iterator;</td> + </tr> + <tr> + <td class=code>iterator </td> + <td class=code>begin (); </td> + </tr> + <tr> + <td class=code>iterator </td> + <td class=code>end ();</td> + </tr> + <tr> + <td class=code>class </td> + <td class=code>const_iterator;</td> + </tr> + <tr> + <td class=code>const_iterator </td> + <td class=code>begin () const;</td> + </tr> + <tr> + <td class=code>const_iterator </td> + <td class=code>end () const;</td> + </tr> +</table> + +<p>Any heir of class Object that has a sequence behavior should inherit from class +SeqBase<T>, where T is specified as the type of object that represents the +individual elements of the sequence. The requirements on T are that it has a constructor +that takes a PyObject* as an argument, that it has a default constructor, a copy +constructor, and an assignment operator. In short, any properly defined heir of Object +will work. </p> + +<h2>Classes Char and String</h2> + +<p>Python strings are unusual in that they are immutable sequences of characters. However, +there is no character type per se; rather, when subscripted strings return a string of +length one. To simulate this, we define two classes Char and String. The Char class +represents a Python string object of length one. The String class represents a Python +string, and its elements make up a sequence of Char's.</p> + +<p>The user interface for Char is limited. Unlike String, for example, it is not a +sequence.</p> + +<h3>The Char interface</h3> + +<p>Char inherits from Object.</p> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Char (PyObject *pyob, bool owned = false)</td> + </tr> + <tr> + <td class=code></td> + <td class=code>Char (const Object& ob) </td> + </tr> + <tr> + <td class=code></td> + <td class=code>Char (const std::string& v = "") </td> + </tr> + <tr> + <td class=code></td> + <td class=code>Char (char v)</td> + </tr> + <tr> + <td class=code></td> + <td class=code>Char (Py_UNICODE v)</td> + </tr> + <tr> + <td class=code>Char&</td> + <td class=code>operator= (const std::string& v)</td> + </tr> + <tr> + <td class=code>Char&</td> + <td class=code>operator= (char v) </td> + </tr> + <tr> + <td class=code>Char&</td> + <td class=code>operator= (Py_UNICODE v) </td> + </tr> + <tr> + <td class=code>Char&</td> + <td class=code>operator= (std::basic_string<Py_UNICODE> v) </td> + </tr> + <tr> + <td class=code></td> + <td class=code>operator String() const</td> + </tr> + <tr> + <td class=code></td> + <td class=code>operator std::string () const </td> + </tr> +</table> + +<h3>The String Interface</h3> + +<p>String inherits from SeqBase<Char>.</p> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + </tr> + <tr> + <td class=code>explicit </td> + <td class=code>String (PyObject *pyob, bool owned = false)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>String (const Object& ob)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>String (const std::string& v = "")</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>String (const std::string& v, const char *encoding, const char *error="strict")</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>String (const char *s, const char *encoding, const char *error="strict")</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>String (const char *s, int len, const char *encoding, const char *error="strict")</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>String (const std::string& v, std::string::size_type vsize)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>String (const char* v)</td> + </tr> + <tr> + <td class=code>String&</td> + <td class=code>operator= (const std::string& v) </td> + </tr> + <tr> + <td class=code>std::string</td> + <td class=code>operator std::string () const</td> + </tr> + <tr> + <td class=code>String</td> + <td class=code>encode( const char *encoding, const char *error="strict" )</td> + </tr> + <tr> + <td class=code>String</td> + <td class=code>decode( const char *encoding, const char *error="strict" )</td> + </tr> + <tr> + <td class=code>std::string</td> + <td class=code>as_std_string() const</td> + </tr> + <tr> + <td class=code>unicodestring</td> + <td class=code>as_unicodestring() const</td> + </tr> +</table> + +<h2>Class Tuple</h2> + +<p>Class Tuple represents Python tuples. A Tuple is a Sequence. There are two kinds of +constructors: one takes a PyObject* as usual, the other takes an integer number as an +argument and returns a Tuple of that length, each component initialized to Py_None. The +default constructor produces an empty Tuple. </p> + +<p>Tuples are not immutable, but attempts to assign to their components will fail if the +reference count is not 1. That is, it is safe to set the elements of a Tuple you have just +made, but not thereafter.</p> + +<p>Example: create a Tuple containing (1, 2, 4)</p> + +<pre>Tuple t(3) +t[0] = Int(1) +t[1] = Int(2) +t[2] = Int(4)</pre> + +<p>Example: create a Tuple from a list:</p> + +<pre>Dict d +... +Tuple t(d.keys())</pre> + +<h3>The Tuple Interface</h3> + +<p>Tuple inherits from Sequence.. Special run-time checks prevent modification if the +reference count is greater than one.</p> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + <th>Comment</td> + </tr> + <tr> + <td class=code>virtual void</td> + <td class=code>setItem (int offset, const Object&ob) </td> + <td>setItem is overriden to handle tuples properly. </td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Tuple (PyObject *pyob, bool owned = false)</td> + <td></td> + </tr> + <tr> + <td class=code> </td> + <td class=code>Tuple (const Object& ob)</td> + <td></td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Tuple (int size = 0)</td> + <td>Create a tuple of the given size. Items initialize to Py_None. Default is an empty + tuple.</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Tuple (const Sequence& s)</td> + <td>Create a tuple from any sequence.</td> + </tr> + <tr> + <td class=code>Tuple&</td> + <td class=code>operator= (const Object& rhs)</td> + <td></td> + </tr> + <tr> + <td class=code>Tuple&</td> + <td class=code>operator= (PyObject* rhsp)</td> + <td></td> + </tr> + <tr> + <td class=code>Tuple</td> + <td class=code>getSlice (int i, int j) const </td> + <td>Equivalent to python's t[i:j]</td> + </tr> +</table> + +<h2>Class List</h2> + +<p>Class List represents a Python list, and the methods available faithfully reproduce the +Python API for lists. A List is a Sequence.</p> + +<h3>The List Interface</h3> + +<p>List inherits from Sequence.</p> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + <th>Comment</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>List (PyObject *pyob, bool owned = false)</td> + <td></td> + </tr> + <tr> + <td class=code> </td> + <td class=code>List (const Object& ob)</td> + <td></td> + </tr> + <tr> + <td class=code> </td> + <td class=code>List (int size = 0)</td> + <td>Create a list of the given size. Items initialized to Py_None. Default is an empty list.</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>List (const Sequence& s)</td> + <td>Create a list from any sequence.</td> + </tr> + <tr> + <td class=code>List&</td> + <td class=code>operator= (const Object& rhs)</td> + <td></td> + </tr> + <tr> + <td class=code>List&</td> + <td class=code>operator= (PyObject* rhsp)</td> + <td></td> + </tr> + <tr> + <td class=code>List</td> + <td class=code>getSlice (int i, int j) const</td> + <td></td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>setSlice (int i, int j, const Object& v) </td> + <td></td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>append (const Object& ob)</td> + <td></td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>insert (int i, const Object& ob)</td> + <td></td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>sort ()</td> + <td>Sorts the list in place, using Python's member function. You can also use + the STL sort function on any List instance.</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>reverse ()</td> + <td>Reverses the list in place, using Python's member function.</td> + </tr> +</table> + +<h1>Mappings</h1> + +<p>A class MapBase<T> is used as the base class for Python objects with a mapping +behavior. The key behavior of this class is the ability to set and use items by +subscripting with strings. A proxy class mapref<T> is defined to produce the correct +behavior for both use and assignment.</p> + +<p>For convenience, <cite>Mapping</cite> is a typedef for <cite>MapBase<Object></cite>.</p> + +<h3>The MapBase<T> interface</h3> + +<p>MapBase<T> inherits from Object. T should be chosen to reflect the kind of +element returned by the mapping.</p> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + <th>Comment</td> + </tr> + <tr> + <td class=code>T</td> + <td class=code>operator[](const std::string& key) const</td> + <td></td> + </tr> + <tr> + <td class=code>mapref<T> </td> + <td class=code>operator[](const std::string& key)</td> + <td></td> + </tr> + <tr> + <td class=code>int</td> + <td class=code>length () const</td> + <td>Number of entries.</td> + </tr> + <tr> + <td class=code>int</td> + <td class=code>hasKey (const std::string& s) const </td> + <td>Is m[s] defined?</td> + </tr> + <tr> + <td class=code>T</td> + <td class=code>getItem (const std::string& s) const</td> + <td>m[s]</td> + </tr> + <tr> + <td class=code>virtual void</td> + <td class=code>setItem (const std::string& s, const Object& ob)</td> + <td>m[s] = ob</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>delItem (const std::string& s)</td> + <td>del m[s]</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>delItem (const Object& s)</td> + <td></td> + </tr> + <tr> + <td class=code>List</td> + <td class=code>keys () const</td> + <td>A list of the keys.</td> + </tr> + <tr> + <td class=code>List</td> + <td class=code>values () const</td> + <td>A list of the values.</td> + </tr> + <tr> + <td class=code>List</td> + <td class=code>items () const</td> + <td>Each item is a key-value pair.</td> + </tr> +</table> + +<h2>Class Dict</h2> + +<p>Class Dict represents Python dictionarys. A Dict is a Mapping. Assignment to +subscripts can be used to set the components.</p> + +<pre>Dict d +d["Paul Dubois"] = "(925)-422-5426"</pre> + +<h3>Interface for Class Dict</h3> + +<p>Dict inherits from MapBase<Object>.</p> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + <th>Comment</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Dict (PyObject *pyob</a>, bool owned = false)</td> + <td></td> + </tr> + <tr> + <td class=code> </td> + <td class=code>Dict (const Dict& ob)</td> + <td></td> + </tr> + <tr> + <td class=code> </td> + <td class=code>Dict () </td> + <td>Creates an empty dictionary</td> + </tr> + <tr> + <td class=code>Dict&</td> + <td class=code>operator= (const Object& rhs)</td> + <td></td> + </tr> + <tr> + <td class=code>Dict&</td> + <td class=code>operator= (PyObject* rhsp)</td> + <td></td> + </tr> +</table> + +<h1>Other classes and facilities.</h1> + +<p>Class Callable provides an interface to those Python objects that support a call +method. Class Module holds a pointer to a module. If you want to create an extension +module, however, see the extension facility. There is a large set of numeric operators.</p> + +<h3>Interface to class Callable</h3> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + <th>Comment</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Callable (PyObject *pyob</a>, bool owned = false)</td> + <td></td> + </tr> + <tr> + <td class=code>Callable& </td> + <td class=code>operator= (const Object& rhs)</td> + <td></td> + </tr> + <tr> + <td class=code>Callable& </td> + <td class=code>operator= (PyObject* rhsp)</td> + <td></td> + </tr> + <tr> + <td class=code>Object</td> + <td class=code>apply(const Tuple& args) const</td> + <td>Call the object with the given arguments</td> + </tr> + <tr> + <td class=code>Object</td> + <td class=code>apply(PyObject* pargs = 0) const </td> + <td>Call the object with args as the arguments. Checks that pargs is a tuple.</td> + </tr> +</table> + +<h3>Interface to class Module</h3> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + <th>Comment</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Module (PyObject* pyob, bool owned = false)</td> + <td></td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>Module (const std::string name)</td> + <td>Construct from name of module; does the import if needed.</td> + </tr> + <tr> + <td class=code></td> + <td class=code>Module (const Module& ob) </td> + <td>Copy constructor</td> + </tr> + <tr> + <td class=code>Module&</td> + <td class=code>operator= (const Object& rhs) </td> + <td>Assignment</td> + </tr> + <tr> + <td class=code>Module&</td> + <td class=code>operator= (PyObject* rhsp) </td> + <td>Assignment</td> + </tr> +</table> + +<h3>Numeric interface</h3> + +<p>Unary operators for plus and minus, and binary operators +, -, *, /, and % are defined +for pairs of objects and for objects with scalar integers or doubles (in either +order). Functions abs(ob) and coerce(o1, o2) are also defined. </p> + +<p>The signature for coerce is:</p> + +<pre>inline std::pair<Object,Object> coerce(const Object& a, const Object& b)</pre> + +<p>Unlike the C API function, this simply returns the pair after coercion.</p> + +<h3>Stream I/O</h3> + +<p>Any object can be printed using stream I/O, using std::ostream& operator<< +(std::ostream& os, const Object& ob). The object's str() representation is +converted to a standard string which is passed to std::ostream& operator<< +(std::ostream& os, const std::string&).</p> + +<h2>Exceptions</h2> + +<p>The Python exception facility and the C++ exception facility can be merged via the use +of try/catch blocks in the bodies of extension objects and module functions.</p> + +<h3>Class Exception and its children</h3> + +<p>A set of classes is provided. Each is derived from class Exception, and represents a +particular sort of Python exception, such as IndexError, RuntimeError, ValueError. Each of +them (other than Exception) has a constructor which takes an explanatory string as an +argument, and is used in a throw statement such as:</p> + +<pre>throw IndexError("Index too large in MyObject access.");</pre> + +<p>If in using a routine from the Python API, you discover that it has returned a NULL +indicating an error, then Python has already set the error message. In that case you +merely throw Exception.</p> + +<h3>List of Exceptions</h3> + +<p>The exception hierarchy mirrors the Python exception hierarchy. The concrete exception +classes are shown here.</p> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</th> + <th>Interface for class Exception</th> + </tr> + <tr> + <td class=code>explicit </td> + <td class=code>Exception()</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>Exception (const std::string& reason) </td> + </tr> + <tr> + <td class=code> </td> + <td class=code>Exception (PyObject* exception, const std::string& reason) </td> + </tr> + <tr> + <td class=code>void </td> + <td class=code>clear()</td> + </tr> + <tr> + <td class=code></td> + <td>Constructors for other children of class Exception</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>TypeError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>IndexError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>AttributeError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>NameError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>RuntimeError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>SystemError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>KeyError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>ValueError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>OverflowError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>ZeroDivisionError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>MemoryError (const std::string& reason)</td> + </tr> + <tr> + <td class=code> </td> + <td class=code>SystemExit (const std::string& reason)</td> + </tr> +</table> + +<h2>Using Exceptions in extension methods</h2> + +<p>The exception facility allows you to integrate the C++ and Python exception mechanisms. +To do this, you must use the style described below when writing module methods in the old +C style. </p> + +<p>Note: If using the ExtensionModule or PythonExtension mechanisms described below, the +method handlers include exception handling so that you only need to use exceptions +explicitly in unusual cases.</p> + +<h3>Catching Exceptions from the Python API or PyCXX.</h3> + +<p>When writing an extension module method, you can use the following boilerplate. Any +exceptions caused by the Python API or PyCXX itself will be converted into a Python +exception. Note that Exception is the most general of the exceptions listed above, and +therefore this one catch clause will serve to catch all of them. You may wish to catch +other exceptions, not in the Exception family, in the same way. If so, you need to make +sure you set the error in Python before returning.</p> + +<pre>static PyObject * +some_module_method(PyObject* self, PyObject* args) +{ + Tuple a(args); // we know args is a Tuple + try { + ...calculate something from a... + return ...something, usually of the form new_reference_to(some Object); + } + catch(const Exception&) { + //Exception caught, passing it on to Python + return Null (); + } +} +</pre> + +<h3>How to clear an Exception</h3> + +<p>If you anticipate that an Exception may be thrown and wish to recover from it, change +the catch phrase to set a reference to an Exception, and use the method clear() from class +Exception to clear it.:</p> + +<pre>catch(Exception& e) + { + e.clear(); + ...now decide what to do about it... + } +</pre> + +<h2>Extension Facilities</h2> + +<p>CXX/Extensions.hxx provides facilities for: + +<ul> + <li>Creating a Python extension module</li> + <li>Creating new Python extension types</li> +</ul> + +<p>These facilities use CXX/Objects.hxx and its support file cxxsupport.cxx.</p> + +<p>If you use CXX/Extensions.hxx you must also include source files cxxextensions.c and +cxx_extensions.cxx</p> + +<h3>Creating an Python extension module</h3> + +<p>The usual method of creating a Python extension module is to declare and initialize its +method table in C. This requires knowledge of the correct form for the table and the order +in which entries are to be made into it, and requires casts to get everything to compile +without warning. The PyCXX header file CXX/Extensions.h offers a simpler method. Here is a +sample usage, in which a module named "example" is created. Note that two +details are necessary: + +<ul> + <li>The initialization function must be declared to have external C linkage and to have the + expected name. This is a requirement imposed by Python</li> + <li>The ExtensionModule object must have a storage class that survives the call to the + initialization function. This is most easily accomplished by using a static local inside + the initialization function, as in initexample below.</li> +</ul> + +<p>To create an extension module, you inherit from class ExtensionModule templated on +yourself: In the constructor, you make calls to register methods of this class with Python +as extension module methods. In this example, two methods are added (this is a simplified +form of the example in Demo/example.cxx):</p> + +<pre>class example_module : public ExtensionModule<example_module> +{ +public: + example_module() + : ExtensionModule<example_module>( "example" ) + { + add_varargs_method("sum", &example_module::ex_sum, "sum(arglist) = sum of arguments"); + add_varargs_method("test", &example_module::ex_test, "test(arglist) runs a test suite"); + + initialize( "documentation for the example module" ); + } + + virtual ~example_module() {} + +private: + Object ex_sum(const Tuple &a) { ... } + Object ex_test(const Tuple &a) { ... } +}; +</pre> + +<p>To initialize the extension, you just instantiate one static instance (static so it +does not destroy itself!):</p> + +<pre>void initexample() +{ +static example_module* example = new example_module; +}</pre> + +<p>The methods can be written to take Tuples as arguments and return Objects. If +exceptions occur they are trapped for you and a Python exception is generated. So, for +example, the implementation of ex_sum might be:</p> + +<pre>Object ex_sum (const Tuple &a) + { + Float f(0.0); + for( int i = 0; i < a.length(); i++ ) + { + Float g(a[i]); + f = f + g; + } + return f; + }</pre> + +<p>class ExtensionModule contains methods to return itself as a Module object, or to +return its dictionary.</p> + +<h3>Interface to class ExtensionModule</h3> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + <th>Comment</td> + </tr> + <tr> + <td class=code>explicit</td> + <td class=code>ExtensionModule (char* name) </td> + <td>Create an extension module named "name"</td> + </tr> + <tr> + <td class=code>virtual </td> + <td class=code>~ExtensionModule () </td> + <td>Destructor</td> + </tr> + <tr> + <td class=code>Dict</td> + <td class=code>moduleDictionary() const</td> + <td>Returns the module dictionary; module must be initialized.</td> + </tr> + <tr> + <td class=code>Module</td> + <td class=code>module() const</td> + <td>This module as a Module.</td> + </tr> + <tr> + <td class=code>void </td> + <td class=code>add_varargs_method (char *name, method_varargs_function_t method, char *documentation="")</td> + <td>Add a method to the module.</td> + </tr> + <tr> + <td class=code>void </td> + <td class=code>add_keyword_method (char *name, method_keyword_function_t method, char *documentation=""</td> + <td>Add a method that takes keywords</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>initialize() (protected, call from constructor)</td> + <td>Initialize the module once all methods have been added. </td> + </tr> +</table> + +<p>The signatures above are:</p> + +<pre>typedef Object (T::*method_varargs_function_t)( const Tuple &args ); +typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws +);</pre> + +<p>That is, the methods take a Tuple or a Tuple and a Dict, and return an Object. The +example below has an & in front of the name of the method; we found one compiler that +needed this.</p> + +<h2>Creating a Python extension type</h2> + +<p>One of the great things about Python is the way you can create your own object types +and have Python welcome them as first-class citizens. Unfortunately, part of the way you +have to do this is not great. Key to the process is the creation of a Python "type +object". All instances of this type must share a reference to this one unique type +object. The type object itself has a multitude of "slots" into which the +addresses of functions can be added in order to give the object the desired behavior. </p> + +<p>Creating extension objects is of course harder since you must specify +how the object behaves and give it methods. This is shown in some detail in the example +range.h and range.cxx, with the test routine rangetest.cxx, in directory Demo. If you have never +created a Python extension before, you should read the Extension manual first and be very +familiar with Python's "special class methods". Then what follows will make more +sense.</p> + +<p>The basic idea is to inherit from PythonExtension templated on your self</p> + +<pre>class MyObject: public PythonExtension<MyObject> {...}</pre> + +<p>As a consequence: + +<ul> + <li>MyObject is a child of PyObject, so that a MyObject* is-a PyObject*. </li> + <li>A static method <cite>check(PyObject*)</cite> is created in class MyObject. This function + returns a boolean, testing whether or not the argument is in fact a pointer to an instance + of MyObject.</li> + <li>The user can connect methods of MyObject to Python so that they are methods on MyObject + objects. Each such method has the signature:<br> + Object method_name (const Tuple& args).</li> + <li>The user can override virtual methods of PythonExtension in order to set behaviors.</li> + <li>A method is created to handle the deletion of an instance if and when its reference + count goes to zero. This method ensures the calling of the class destructor ~MyObject(), + if any, and releases the memory (see below).</li> + <li>Both automatic and heap-based instances of MyObject can be created.</li> +</ul> + +<h3>Sample usage of PythonExtension</h3> + +<p>Here is a brief overview. You create a class that inherits from PythonExtension +templated upon itself. You override various methods from PythonExtension to implement +behaviors, such as getattr, sequence_item, etc. You can also add methods to the object +that are usable from Python using a similar scheme as for module methods above. </p> + +<p>One of the consequences of inheriting from PythonExtension is that you are inheriting +from PyObject itself. So your class is-a PyObject and instances of it can be passed to the +Python C API. Note: this example uses the namespace feature of PyCXX.</p> + +<p>Hint: You can avoid needing to specify the Py:: prefix if you include the C++ statement +<cite>using Py;</cite> at the top of your files.</p> + +<pre>class range: public Py::PythonExtension<range> { +public: + ... constructors, data, etc. + ... methods not callable from Python + // initializer, see below + static void init_type(); + // override functions from PythonExtension + virtual Py::Object repr(); + virtual Py::Object getattr( const char *name ); + + virtual int sequence_length(); + virtual Py::Object sequence_item( int i ); + virtual Py::Object sequence_concat( const Py::Object &j ); + virtual Py::Object sequence_slice( int i, int j ); + + // define python methods of this object + Py::Object amethod (const Py::Tuple& args); + Py::Object value (const Py::Tuple& args); + Py::Object assign (const Py::Tuple& args); +};</pre> + +<p> +To initialize the type we provide a static method that we can call from some module's +initializer. We set the name, doc string, and indicate which behaviors range objects +support. Then we adds the methods.</p> + +<pre>void range::init_type() +{ + behaviors().name("range"); + behaviors().doc("range objects: start, stop, step"); + behaviors().supportRepr(); + behaviors().supportGetattr(); + behaviors().supportSequenceType(); + + add_varargs_method("amethod", &range::amethod, + "demonstrate how to document amethod"); + add_varargs_method("assign", &range::assign); + add_varargs_method("value", &range::value); +}</pre> +</a> + +<p>Do not forget to add the call range::init_type() to some module's init function. You will want +a method in some module that can create range objects, too.</p> + +<h3>Interface to PythonExtension <T></h3> + +<p>Your extension class T inherits PythonExtension<T>.</p> + +<table cellspacing=0 cellpadding=3px width="95%"> + <tr> + <th>Type</td> + <th>Name</td> + <th>Comment</td> + </tr> + <tr> + <td class=code>virtual </td> + <td class=code>~PythonExtension<T>() </td> + <td>Destructor</td> + </tr> + <tr> + <td class=code>PyTypeObject* </td> + <td class=code>type_object() const</td> + <td>Returns the object type object.</td> + </tr> + <tr> + <td class=code>int</td> + <td class=code>check (PyObject* p)</td> + <td>Is p a T?</td> + </tr> + <tr> + <td colspan="3"><strong>Protected </strong></td> + </tr> + <tr> + <td class=code>void </td> + <td class=code>add_varargs_method (char *name, method_keyword_function_t method, char *documentation=""</td> + <td>Add a method that takes arguments</td> + </tr> + <tr> + <td class=code>void </td> + <td class=code>add_keyword_method (char *name, method_keyword_function_t method, char *documentation=""</td> + <td>Add a method that takes keywords</td> + </tr> + <tr> + <td class=code>static PythonType&</td> + <td class=code>behaviors()</td> + <td>The type object</td> + </tr> + <tr> + <td class=code>void</td> + <td class=code>initialize() (protected, call from constructor)</td> + <td>Initialize the module once all methods have been added. </td> + </tr> +</table> + +<p>As before the signatures for the methods are Object mymethod(const Tuple& +args) and Object mykeywordmethod (const Tuple& args, const Dict& keys). In this +case, the methods must be methods of T.</p> + +<p>To set the behaviors of the object you override some or all of these methods from +PythonExtension<T>:</p> + +<pre> virtual int print( FILE *, int ); + virtual Object getattr( const char * ); + 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* );</pre> + +<p>Note that dealloc is not one of the functions you can override. That is what your +destructor is for. As noted below, dealloc behavior is provided for you by +PythonExtension.</p> + +<h3>Type initialization</h3> + +<p>To initialize your type, supply a static public member function that can be called +from the extension module. In that function, obtain the PythonType object by calling +behaviors() and apply appropriate "support" methods from PythonType to turn on +the support for that behavior or set of behaviors.</p> + +<pre> 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);</pre> + +<p>Then call add_varargs_method or add_keyword_method to add any methods desired to the +object.</p> + +<h3>Notes on memory management and extension objects</h3> + +<p>Normal Python objects exist only on the heap. That is unfortunate, as object creation +and destruction can be relatively expensive. Class PythonExtension allows creation of both +local and heap-based objects.</p> + +<p>If an extension object is created using operator new, as in:</p> + +<pre>range* my_r_ref = new range(1, 20, 3)</pre> + +<p>then the entity my_r_ref can be thought of as "owning" the reference created +in the new object. Thus, the object will never have a reference count of zero. If the +creator wishes to delete this object, they should either make sure the reference count is +1 and then do delete my_r_ref, or decrement the reference with Py_DECREF(my_r_ref).</p> + +<p>Should my_r_ref give up ownership by being used in an Object constructor, all will +still be well. When the Object goes out of scope its destructor will be called, and that +will decrement the reference count, which in turn will trigger the special dealloc routine +that calls the destructor and deletes the pointer.</p> + +<p>If the object is created with automatic scope, as in:</p> + +<pre>range my_r(1, 20, 3)</pre> + +<p>then my_r can be thought of as owning the reference, and when my_r goes out of scope +the object will be destroyed. Of course, care must be taken not to have kept any permanent +reference to this object. Fortunately, in the case of an exception, the C++ exception +facility will call the destructor of my_r. Naturally, care must be taken not to end up +with a dangling reference, but such objects can be created and destroyed more efficiently +than heap-based PyObjects.</p> + +<h2>Putting it all together</h2> + +<p>The Demo directory of the distribution contains an extensive example of how to use many +of the facilities in PyCXX. It also serves as a test routine. This test is not completely +exhaustive but does excercise much of the facility.</p> + +<h2>Acknowledgment</h2> + +<p>Thank you to Geoffrey Furnish for patiently teaching me the finer points of C++ and its +template facility, and his critique of PyCXX in particular. With version 4 I welcome Barry +Scott as co-author. -- Paul Dubois</p> + +</body> +</html> diff --git a/lib/kross/python/cxx/README.html b/lib/kross/python/cxx/README.html new file mode 100644 index 00000000..d698725a --- /dev/null +++ b/lib/kross/python/cxx/README.html @@ -0,0 +1,436 @@ +<html> + +<head> +<title>PyCXX README</title> + +<style> +H1, H2, H3, H4 {color: #000099; + background-color: lightskyblue} +h3 {position: relative; left: 20px} + +p {position: relative; left: 20px; margin-right: 20px} +pre {color: #0000cc; background-color: #eeeeee; position: relative; left: 40px; margin-right: 80px; + border-style: solid; border-color: black; border-width: thin} +kbd {color: #990000} +p cite, ol cite, ul cite {font-family: monospace; font-style: normal; font-size: normal} +li var, pre var, p var, kbd var {color: #009900; font-style: italic} +li samp, pre samp, p samp, kbd samp {color: #009900; font-weight: bold} +li p {position: relative; left: 0} +table { position: relative; left: 20px; border: solid #888888 1px; background-color: #eeeeee} +table th {border: solid #888888 1px; background-color: #88dd88; color: black} +table td {border: solid #888888 1px} +table td.code {border: solid #888888 1px;font-family: monospace; font-style: normal; font-size: normal} +p.param {background-color: #eeeeee; border-top: lightskyblue solid 4} +</style> +</head> + +<body> + +<h1>PyCXX -- Python C++ Extensions Support</h1> + +<h2>Installation using distutils</h2> + +<h3>Windows Installation and Demo</h3> +<ol> +<li>Fetch <a href="http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz"> +http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz</a> +<li>Expand the archive into a directory of your choosing C:\ for example. Note: WinZip can expand .tar.gz files. +<li>Install the PyCXX files: +<ol> +<li><pre>C:> cd \pycxx_5_3_1</pre> +<li><pre>C:\pycxx_5_3_1> python setup.py install</pre> +</ol> +<li>Install the PyCXX Demo: +<ol> +<li><pre>C:> cd \PYCXX_5_3_1\Demo</pre> +<li><pre>C:\PYCXX_5_3_1\Demo> python setup.py install</pre> +</ol> +<li>Run the demo: +<ol> +<li><pre>C:> python</pre> +<li><pre>>>> import CXX.example</pre> +<li><pre>>>> CXX.example.test()</pre> +<li><pre>>>> r = CXX.example.range( 11, 100, 13 )</pre> +<li><pre>>>> for i in r: print i</pre> +<li><pre>...</pre> +</ol> +</ul> +</ol> + + +<h3>Unix Installation and Demo</h3> +<p>Note: distutils is not available for Python 1.5.2</p> + +<ol> +<li>Fetch <a href="http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz"> +http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz</a> +<li>Login as root. root access is typically needed on Unix systems to install the PyCXX files into the Python directories. +<li>Expand the archive into a directory of your choosing ~\ for example. +<li>Install the PyCXX files: +<ol> +<li><pre># cd ~\PYCXX_5_3_1</pre> +<li><pre># python setup.py install</pre> +</ol> +<li>Install the PyCXX Demo: +<ol> +<li><pre># cd ~\PYCXX_5_3_1\Demo</pre> +<li><pre># python setup.py install</pre> +</ol> +<li>Run the demo: +<ol> +<li><pre>~ python</pre> +<li><pre>>>> import CXX.example</pre> +<li><pre>>>> CXX.example.test()</pre> +<li><pre>>>> r = CXX.example.range( 11, 100, 13 )</pre> +<li><pre>>>> for i in r: print i</pre> +<li><pre>...</pre> +</ol> +</ul> +</ol> + +<h2>Installation using Project and Makefile</h2> + +<p>If you cannot or do not wish to use the distutils methods to work with PyCXX a set +of Makefiles and Project files are provided.</p> + +<h3>Windows Installation and Demo</h3> +<p> +<ol> +<li>Fetch <a href="http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz"> +http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz</a> +<li>Expand the archive into a directory of your choosing C:\ for example. WinZip can expand .tar.gz files. +<li>Build the example. Using Microsoft Visual C++ 6.0 load the workspace corresponsing to the version of +Python you wish the work with. +<ul> +<li>example_py15.dsw - Python 1.5.2 +<li>example_py20.dsw - Python 2.0 and 2.0.1 +<li>example_py21.dsw - Python 2.1 and 2.1.1 +<li>example_py22.dsw - Python 2.2 and its maintanence release +<li>example_py23.dsw - Python 2.3 and its maintanence release +</ul> +<li>Run the example. (I'll assume you are testing Python 2.3) +<ul> +<li>cd c:\PYCXX_5_3_1\pyds23 +<li>c:\python21\python -c "import example;example.test()" +</ul> +</ol> +</p> +<h3>Unix Installation and Demo</h3> +<p> +<ol> +<li>Fetch <a href="http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz"> +http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz</a> +<li>Expand the archive into a directory of your choosing ~/ for example. +<li>Select to makefile for your system and python version. +<ul> +<li>example_freebsd_py15.mak - FreeBSD Python 1.5.2 (see <a href="#note_1_5_2">note</a> below) +<li>example_freebsd_py20.mak - FreeBSD Python 2.0, 2.0.1 +<li>example_freebsd_py21.mak - FreeBSD Python 2.1, 2.1.1 +<li>example_freebsd_py22.mak - FreeBSD Python 2.2 +<li>example_linux_py15.mak - Linux Python 1.5.2 +<li>example_linux_py20.mak - Linux Python 2.0, 2.0.1 +<li>example_linux_py21.mak - Linux Python 2.1, 2.1.1 +<li>example_linux_py22.mak - Linux Python 2.2 +</ul> +<li>Build the example. Use GNU make<br> +$ make -f <var>example-makefile</var> example.so +<li>Run the example.<br> +$ make -f <var>example-makefile</var> test +</ol> +</p> + +<p><a id="note_1_5_2">Note:</a> The Unix version of python 1.5.2 may need to be rebuilt so that C++ is support. +If you get reports of undefined symbols like cout or cerr then its likely that python +is not compiled and linked to support C and C++.</p> + +<p>To create a makefile for another vendors Unix follow these steps:</p> +<ol> +<li>copy one of the example make files above. +<li>edit the variables to match your Python installation and C++ compile needs +<li>Proceed to build and test as above. +</ol> +<p>Note: most of the makefile rules to build PyCXX and its example are contained in example_common.mak. +</p> + +<h2>Revision History</h2> +<h3>Version 5.3.1 (19-Jan-2005)</h3> +<p>Support GCC4 and Microsoft .NET 2003 aka MSVC 7.1 + +<h3>Version 5.3 (21-Oct-2004)</h3> +<p>String object now support python string and unicode string objects. +<p>Fix most bugs reported on SourceForge + +<h3>Version 5.2 (27-Nov-2003)</h3> +<p>PyCXX supports Python version 2.3, 2.2, 2.1, 2.0 and 1.5.2 on Windows and Unix.</p> +<p>Fixed problems with keyword functions.</p> +<p>Improve Extension API to give access to names and docs +<p>Support GCC 3.</p> +<p>Added support for custom Exceptions</p> +<p></p> + +<h3>Version 5.1 (2-Aug-2001)</h3> +<p>I'm using the name PyCXX for this package, CXX is far to close to a compilers name.</p> + +<p>PyCXX supports Python version 2.2, 2.1.1, 2.1, 2.0, 2.0.1 and 1.5.2 on Windows and Unix.</p> + +<p>New in this release:</p> +<ul> +<li>Support for the Windows Linker /DELAYLOAD feature. Enable this feature by +defining PY_WIN32_DELAYLOAD_PYTHON_DLL when compiling IndirectPythonInterface.cxx +<li>Remove "CXX/Array.hxx" and associated code - its does not belong in PyCXX +<li>Work on the docs. Mostly to clean up the HTML to allow more extensive work. +<li>Reformated the sources to a consistent style. The mix of styles and tabs sizes +was making working on the sources error prone. +<li>Added workaround to setup.py to allow GCC to compile c++ code. +<li>Added Microsoft Visual C++ 6.0 project files for 1.5, 2.0 and 2.1 builds +<li>Added Unix make files for Linux (tested on RedHat 7.1) and FreeBSD (tested on 4.3) +<li>Merged changes from Tom Malcolmson +</ul> + +<h3>(July 9, 2000)</h3> +<p>Renamed all header files to reflect the CXX include name space and that they are +C++ header files. +<p> +<table cellspacing=0 cellpadding=3px> +<tr><th>Old</th><th>New</th></tr> +<tr><td>#include "CXX_Config.h"</td><td>#include "CXX/Config.hxx"</td> +<tr><td>#include "CXX_Exception.h"</td><td>#include "CXX/Exception.hxx"</td> +<tr><td>#include "CXX_Extensions.h"</td><td>#include "CXX/Extensions.hxx"</td> +<tr><td>#include "CXX_Objects.h"</td><td>#include "CXX/Objects.hxx"</td> +</table> + +<h3>Version 5 (May 18, 2000)</h3> +<p>This version adds Distutils support for installation and some code cleanup.</p> + +<h3>Version 4 (October 11, 1999)</h3> + +<p>This version contains a massive revision to the part of CXX that supports creating +extension objects and extension modules. Barry Scott contributed these changes.</p> + +<p>CXX has always consisted of two parts: the basic CXX_Objects.h and the more +experimental CXX_Extensions.h. We will describe the changes to CXX_Objects first, and then +the changes to CXX_Extensions.h.</p> + +<h3>Changes to CXX_Objects</h3> + +<h4>1. Owned option eliminates need for FromAPI in most cases</h4> + +<p>Object's constructor from PyObject* and method set have a new (backward compatible) +signature:</p> + +<pre> +Object (PyObject* pyob, bool owned = false); +void set(PyObject* pyob, bool owned = false); +</pre> + +<p>Users may call these with owned = true if they own the reference pyob already and want +the Object instance to take over ownership.</p> + +<p>A new inline function Object asObject(PyObject* pyob) returns Object(pyob, true); thus, +one way to construct an object from a pointer returned by the Python API is to call +asObject on it. </p> + +<p>Previously a class FromAPI was provided to solve the problem of taking over an owned +reference. FromAPI will be eliminated in the next release. It is no longer used by CXX +itself or its demos. The new mechanism is much cleaner and more efficient.</p> + +<p>Other classes in CXX have been given the same "owned" option on their +constructors: Int, Float, Long, Complex, SeqBase<T>, Tuple, List, Dict, Module, +Callable.</p> + +<h4>2. Namespace support in compiler assumed</h4> + +<p>Since EGCS / GCC now supports namespaces and the standard library, the need for +CXX_config.h is almost gone. We have eliminated all the macros except for one obscure one +dealing with iterator traits in the standard library.</p> + +<h3>Changes to CXX_Extensions</h3> + +<p>The changes to CXX_Extensions.h are not backward compatible. However, they simplify +coding so much that we think it is worth the disruption.</p> + +<h4>1. Creating an extension module</h4> + +<p>To create an extension module, you inherit from class ExtensionModule templated on +yourself: In the constructor, you make calls to register methods of this class with Python +as extension module methods. In this example, two methods are added (this is a simplified +form of the example in Demo/example.cxx):</p> + +<pre>class example_module : public ExtensionModule<example_module> +{ +public: + example_module() + : ExtensionModule<example_module>( "example" ) + { + add_varargs_method("sum", &example_module::ex_sum, "sum(arglist) = sum of arguments"); + add_varargs_method("test", &example_module::ex_test, "test(arglist) runs a test suite"); + + initialize( "documentation for the example module" ); + } + + virtual ~example_module() {} + +private: + Object ex_sum (const Tuple &a) { ... } + Object ex_test( const Tuple &a) { ... } +}; +</pre> + +<p>To initialize the extension, you just instantiate one static instance (static so it +doesn't destroy itself!):</p> + +<pre> +void initexample() + { + static example_module* example = new example_module; + } +</pre> + +<p>The methods can be written to take Tuples as arguments and return Objects. If +exceptions occur they are trapped for you and a Python exception is generated. So, for +example, the implementation of ex_sum might be:</p> + +<pre> +Object ex_sum (const Tuple &a) + { + Float f(0.0); + for( int i = 0; i < a.length(); i++ ) + { + Float g(a[i]); + f = f + g; + } + return f; + } +</pre> + +<p>class ExtensionModule contains methods to return itself as a Module object, or to +return its dictionary.</p> + +<h4>Creating extension objects</h4> + +<p>Creating extension objects is of course harder since you must specify how the object +behaves and give it methods. This is shown in some detail in the example range.h and range.cxx, +with the test routine rangetest.cxx, in directory Demo.</p> + +<p>Here is a brief overview. You create a class that inherits from PythonExtension +templated upon itself. You override various methods from PythonExtension to implement +behaviors, such as getattr, sequence_item, etc. You can also add methods to the object +that are usable from Python using a similar scheme as for module methods above. </p> + +<p>One of the consequences of inheriting from PythonExtension is that you are inheriting +from PyObject itself. So your class is-a PyObject and instances of it can be passed to the +Python C API. Note: this example uses the namespace feature of CXX. The Py:: 's are not +required if you use the namespace instead.</p> + +<pre> +class range: public Py::PythonExtension<range> { +public: + ... constructors, etc. + + ... methods + // initializer, see below + static void init_type(); + // override functions from PythonExtension + virtual Py::Object repr(); + virtual Py::Object getattr( const char *name ); + + virtual int sequence_length(); + virtual Py::Object sequence_item( int i ); + virtual Py::Object sequence_concat( const Py::Object &j ); + virtual Py::Object sequence_slice( int i, int j ); + + // define python methods of this object + Py::Object amethod (const Py::Tuple& args); + Py::Object value (const Py::Tuple& args); + Py::Object assign (const Py::Tuple& args); +}; +</pre> + +<p> +To initialize the type you provide a static method that you can call from some module's +initializer. This method sets the name, doc string, and indicates which behaviors it +supports. It then adds the methods.</p> + +<pre> +void range::init_type() +{ + behaviors().name("range"); + behaviors().doc("range objects: start, stop, step"); + behaviors().supportRepr(); + behaviors().supportGetattr(); + behaviors().supportSequenceType(); + + add_varargs_method("amethod", &range::amethod, + "demonstrate how to document amethod"); + add_varargs_method("assign", &range::assign); + add_varargs_method("value", &range::value); +} +</pre> + +<h3>Version 3 (June 18, 1999)</h3> + +<p>1. CXX compiles with EGCS snapshot 19990616. EGCS requires a standard library class +random_access_iterator that is not yet available in some other compilers (such as Windows +VC6). Therefore a new switch:</p> + +<p>STANDARD_LIBRARY_HAS_ITERATOR_TRAITS</p> + +<p>has been added to CXX_Config.h that you may need to toggle if you get an error on the +two lines that mention random_access_iterator. The current definition is correct for VC6 +and EGCS-19990616. </p> + +<p>2. A new constructor was added to Module to allow construction from a string containing +the module name. A test was added for this to the demo.</p> + +<h3>Version 2 (Dec. 28, 1998)</h3> + +<p>Fixed definition of extension type to match 1.5.2. This version will presumably not +compile with older versions of Python. This can be fixed by using the previous version's +definition. I did not take the time to find out what these new "flags" are for +nor put in any methods to deal with them.</p> + +<h3>Version 1</h3> + +<p>This is an experimental set of files for supporting the creation of Python extensions +in C++. </p> + +<p>Documentation is in progress at <a href="http://xfiles.llnl.gov">http://xfiles.llnl.gov</a>. +</p> + +<p>To use CXX you use the header files in Include, such as CXX_Objects.h or +CXX_Extensions.h. You must include the sources in Src in your sources to supply parts of +the CXX classes required.</p> + +<p>A demo is included. The Setup file in this directory compiles this demo named +"example". To try the demo, which is also a test routine, you import example and +then execute:</p> + +<pre> +example.test() +</pre> + +<p>You can also play with the extension object whose constructor is named "range":</p> + +<pre> +s = range(1, 100, 2) +print s[2] # should print 5 +</pre> + +<p>Compilation with Microsoft Visual C++ 5.0 will succeed but only if you have Service +Pack 3 installed. Compilation has been known to succeed on a Unix system using KCC by +using:</p> + +<pre> +setenv CCC "KCC -x" +</pre> + +<p>before running makethis.py.</p> + +<p>There is also a python.cxx file for making a stand-alone Python containing this +example, as well as a similar file arraytest.cxx for testing Array.</p> + +<p>Comments to [email protected], please.</p> + +<p>Barry Scott</p> +</body> +</html> diff --git a/lib/kross/python/cxx/Readme.Kross.txt b/lib/kross/python/cxx/Readme.Kross.txt new file mode 100644 index 00000000..ec00230a --- /dev/null +++ b/lib/kross/python/cxx/Readme.Kross.txt @@ -0,0 +1,16 @@ +Kross uses PyCXX 5.3.1 (http://cxx.sourceforge.net/) +to access the Python C API. + +Following patches where applied and send back to the PyCXX team. + +- Unsigned patch + http://sourceforge.net/tracker/index.php?func=detail&aid=1085205&group_id=3180&atid=303180 +- isInstance patch + http://sourceforge.net/tracker/index.php?func=detail&aid=1178048&group_id=3180&atid=303180 +- dir patch + http://sourceforge.net/tracker/index.php?func=detail&aid=1186676&group_id=3180&atid=303180 +- fixed typos + http://sourceforge.net/tracker/index.php?func=detail&aid=1266579&group_id=3180&atid=103180 + http://sourceforge.net/tracker/index.php?func=detail&aid=1293777&group_id=3180&atid=103180 + +I also changed the includes to get PyCXX compiled the way we use it. diff --git a/lib/kross/python/cxx/Version.txt b/lib/kross/python/cxx/Version.txt new file mode 100644 index 00000000..27be42b3 --- /dev/null +++ b/lib/kross/python/cxx/Version.txt @@ -0,0 +1 @@ +PyCxx 5.3.1 diff --git a/lib/kross/python/cxx/cxx_extensions.cxx b/lib/kross/python/cxx/cxx_extensions.cxx new file mode 100644 index 00000000..f9c942ad --- /dev/null +++ b/lib/kross/python/cxx/cxx_extensions.cxx @@ -0,0 +1,1287 @@ +#include "Extensions.hxx" +#include "Exception.hxx" + +#include <assert.h> + +namespace Py +{ + +//================================================================================ +// +// Implementation of MethodTable +// +//================================================================================ + +PyMethodDef MethodTable::method( const char* method_name, PyCFunction f, int flags, const char* doc ) + { + PyMethodDef m; + m.ml_name = const_cast<char*>( method_name ); + m.ml_meth = f; + m.ml_flags = flags; + m.ml_doc = const_cast<char*>( doc ); + return m; + } + +MethodTable::MethodTable() + { + t.push_back( method( 0, 0, 0, 0 ) ); + mt = 0; + } + +MethodTable::~MethodTable() + { + delete [] mt; + } + +void MethodTable::add( const char* method_name, PyCFunction f, const char* doc, int flag ) + { + if( !mt ) + { + t.insert( t.end()-1, method( method_name, f, flag, doc ) ); + } + else + { + throw RuntimeError( "Too late to add a module method!" ); + } + } + +PyMethodDef* MethodTable::table() + { + if( !mt ) + { + int t1size = t.size(); + mt = new PyMethodDef[t1size]; + int j = 0; + for( std::vector<PyMethodDef>::iterator i = t.begin(); i != t.end(); i++ ) + { + mt[j++] = *i; + } + } + return mt; + } + +//================================================================================ +// +// Implementation of ExtensionModule +// +//================================================================================ +ExtensionModuleBase::ExtensionModuleBase( const char *name ) + : module_name( name ) + , full_module_name( __Py_PackageContext() != NULL ? std::string( __Py_PackageContext() ) : module_name ) + , method_table() + {} + +ExtensionModuleBase::~ExtensionModuleBase() + {} + +const std::string &ExtensionModuleBase::name() const + { + return module_name; + } + +const std::string &ExtensionModuleBase::fullName() const + { + return full_module_name; + } + +class ExtensionModuleBasePtr : public PythonExtension<ExtensionModuleBasePtr> + { +public: + ExtensionModuleBasePtr( ExtensionModuleBase *_module ) + : module( _module ) + {} + virtual ~ExtensionModuleBasePtr() + {} + + ExtensionModuleBase *module; + }; + + +void ExtensionModuleBase::initialize( const char *module_doc ) + { + PyObject *module_ptr = new ExtensionModuleBasePtr( this ); + + Py_InitModule4 + ( + const_cast<char *>( module_name.c_str() ), // name + method_table.table(), // methods + const_cast<char *>( module_doc ), // docs + module_ptr, // pass to functions as "self" + PYTHON_API_VERSION // API version + ); + } + +Py::Module ExtensionModuleBase::module(void) const + { + return Module( full_module_name ); + } + +Py::Dict ExtensionModuleBase::moduleDictionary(void) const + { + return module().getDict(); + } + +//-------------------------------------------------------------------------------- + +//================================================================================ +// +// Implementation of PythonType +// +//================================================================================ + +extern "C" + { + static void standard_dealloc(PyObject* p); + // + // All the following functions redirect the call from Python + // onto the matching virtual function in PythonExtensionBase + // + static int print_handler (PyObject*, FILE *, int); + static PyObject* getattr_handler (PyObject*, char*); + static int setattr_handler (PyObject*, char*, PyObject*); + static PyObject* getattro_handler (PyObject*, PyObject*); + static int setattro_handler (PyObject*, PyObject*, PyObject*); + static int compare_handler (PyObject*, PyObject*); + static PyObject* repr_handler (PyObject*); + static PyObject* str_handler (PyObject*); + static long hash_handler (PyObject*); + static PyObject* call_handler (PyObject*, PyObject*, PyObject*); + +#if PY_VERSION_HEX < 0x02050000 + typedef int Py_ssize_t; +#endif + // Sequence methods + static Py_ssize_t sequence_length_handler(PyObject*); + static PyObject* sequence_concat_handler(PyObject*,PyObject*); + static PyObject* sequence_repeat_handler(PyObject*, Py_ssize_t); + static PyObject* sequence_item_handler(PyObject*, Py_ssize_t); + static PyObject* sequence_slice_handler(PyObject*, Py_ssize_t, Py_ssize_t); + static int sequence_ass_item_handler(PyObject*, Py_ssize_t, PyObject*); + static int sequence_ass_slice_handler(PyObject*, Py_ssize_t, Py_ssize_t, PyObject*); + // Mapping + static Py_ssize_t mapping_length_handler(PyObject*); + static PyObject* mapping_subscript_handler(PyObject*, PyObject*); + static int mapping_ass_subscript_handler(PyObject*, PyObject*, PyObject*); + + // Numeric methods + static int number_nonzero_handler (PyObject*); + static PyObject* number_negative_handler (PyObject*); + static PyObject* number_positive_handler (PyObject*); + static PyObject* number_absolute_handler (PyObject*); + static PyObject* number_invert_handler (PyObject*); + static PyObject* number_int_handler (PyObject*); + static PyObject* number_float_handler (PyObject*); + static PyObject* number_long_handler (PyObject*); + static PyObject* number_oct_handler (PyObject*); + static PyObject* number_hex_handler (PyObject*); + static PyObject* number_add_handler (PyObject*, PyObject*); + static PyObject* number_subtract_handler (PyObject*, PyObject*); + static PyObject* number_multiply_handler (PyObject*, PyObject*); + static PyObject* number_divide_handler (PyObject*, PyObject*); + static PyObject* number_remainder_handler (PyObject*, PyObject*); + static PyObject* number_divmod_handler (PyObject*, PyObject*); + static PyObject* number_lshift_handler (PyObject*, PyObject*); + static PyObject* number_rshift_handler (PyObject*, PyObject*); + static PyObject* number_and_handler (PyObject*, PyObject*); + static PyObject* number_xor_handler (PyObject*, PyObject*); + static PyObject* number_or_handler (PyObject*, PyObject*); + static PyObject* number_power_handler(PyObject*, PyObject*, PyObject*); + + // Buffer + static Py_ssize_t buffer_getreadbuffer_handler (PyObject*, Py_ssize_t, void**); + static Py_ssize_t buffer_getwritebuffer_handler (PyObject*, Py_ssize_t, void**); + static Py_ssize_t buffer_getsegcount_handler (PyObject*, Py_ssize_t*); + } + + +extern "C" void standard_dealloc( PyObject* p ) + { + PyMem_DEL( p ); + } + +void PythonType::supportSequenceType() + { + if( !sequence_table ) + { + sequence_table = new PySequenceMethods; + table->tp_as_sequence = sequence_table; + sequence_table->sq_length = sequence_length_handler; + sequence_table->sq_concat = sequence_concat_handler; + sequence_table->sq_repeat = sequence_repeat_handler; + sequence_table->sq_item = sequence_item_handler; + sequence_table->sq_slice = sequence_slice_handler; + + sequence_table->sq_ass_item = sequence_ass_item_handler; // BAS setup seperately? + sequence_table->sq_ass_slice = sequence_ass_slice_handler; // BAS setup seperately? + } + } + +void PythonType::supportMappingType() + { + if( !mapping_table ) + { + mapping_table = new PyMappingMethods; + table->tp_as_mapping = mapping_table; + mapping_table->mp_length = mapping_length_handler; + mapping_table->mp_subscript = mapping_subscript_handler; + mapping_table->mp_ass_subscript = mapping_ass_subscript_handler; // BAS setup seperately? + } + } + +void PythonType::supportNumberType() + { + if( !number_table ) + { + number_table = new PyNumberMethods; + table->tp_as_number = number_table; + number_table->nb_add = number_add_handler; + number_table->nb_subtract = number_subtract_handler; + number_table->nb_multiply = number_multiply_handler; + number_table->nb_divide = number_divide_handler; + number_table->nb_remainder = number_remainder_handler; + number_table->nb_divmod = number_divmod_handler; + number_table->nb_power = number_power_handler; + number_table->nb_negative = number_negative_handler; + number_table->nb_positive = number_positive_handler; + number_table->nb_absolute = number_absolute_handler; + number_table->nb_nonzero = number_nonzero_handler; + number_table->nb_invert = number_invert_handler; + number_table->nb_lshift = number_lshift_handler; + number_table->nb_rshift = number_rshift_handler; + number_table->nb_and = number_and_handler; + number_table->nb_xor = number_xor_handler; + number_table->nb_or = number_or_handler; + number_table->nb_coerce = 0; + number_table->nb_int = number_int_handler; + number_table->nb_long = number_long_handler; + number_table->nb_float = number_float_handler; + number_table->nb_oct = number_oct_handler; + number_table->nb_hex = number_hex_handler; + } + } + +void PythonType::supportBufferType() + { + if( !buffer_table ) + { + buffer_table = new PyBufferProcs; + table->tp_as_buffer = buffer_table; + buffer_table->bf_getreadbuffer = buffer_getreadbuffer_handler; + buffer_table->bf_getwritebuffer = buffer_getwritebuffer_handler; + buffer_table->bf_getsegcount = buffer_getsegcount_handler; + } + } + +// if you define one sequence method you must define +// all of them except the assigns + +PythonType::PythonType( size_t basic_size, int itemsize, const char *default_name ) + : table( new PyTypeObject ) + , sequence_table( NULL ) + , mapping_table( NULL ) + , number_table( NULL ) + , buffer_table( NULL ) + { + *reinterpret_cast<PyObject*>( table ) = py_object_initializer; + table->ob_type = _Type_Type(); + table->ob_size = 0; + table->tp_name = const_cast<char *>( default_name ); + table->tp_basicsize = basic_size; + table->tp_itemsize = itemsize; + table->tp_dealloc = ( destructor ) standard_dealloc; + table->tp_print = 0; + table->tp_getattr = 0; + table->tp_setattr = 0; + table->tp_compare = 0; + table->tp_repr = 0; + table->tp_as_number = 0; + table->tp_as_sequence = 0; + table->tp_as_mapping = 0; + table->tp_hash = 0; + table->tp_call = 0; + table->tp_str = 0; + table->tp_getattro = 0; + table->tp_setattro = 0; + table->tp_as_buffer = 0; + table->tp_flags = 0L; + table->tp_doc = 0; +#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 0) + // first use in 2.0 + table->tp_traverse = 0L; + table->tp_clear = 0L; +#else + table->tp_xxx5 = 0L; + table->tp_xxx6 = 0L; +#endif +#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) + // first defined in 2.1 + table->tp_richcompare = 0L; + table->tp_weaklistoffset = 0L; +#else + table->tp_xxx7 = 0L; + table->tp_xxx8 = 0L; +#endif + +#ifdef COUNT_ALLOCS + table->tp_alloc = 0; + table->tp_free = 0; + table->tp_maxalloc = 0; + table->tp_next = 0; +#endif + } + +PythonType::~PythonType( ) + { + delete table; + delete sequence_table; + delete mapping_table; + delete number_table; + delete buffer_table; + } + +PyTypeObject* PythonType::type_object( ) const + {return table;} + +void PythonType::name( const char* nam ) + { + table->tp_name = const_cast<char *>( nam ); + } + +const char *PythonType::getName() const + { + return table->tp_name; + } + +void PythonType::doc( const char* d ) + { + table->tp_doc = const_cast<char *>( d ); + } + +const char *PythonType::getDoc() const + { + return table->tp_doc; + } + +void PythonType::dealloc( void( *f )( PyObject* )) + { + table->tp_dealloc = f; + } + +void PythonType::supportPrint() + { + table->tp_print = print_handler; + } + +void PythonType::supportGetattr() + { + table->tp_getattr = getattr_handler; + } + +void PythonType::supportSetattr() + { + table->tp_setattr = setattr_handler; + } + +void PythonType::supportGetattro() + { + table->tp_getattro = getattro_handler; + } + +void PythonType::supportSetattro() + { + table->tp_setattro = setattro_handler; + } + +void PythonType::supportCompare() + { + table->tp_compare = compare_handler; + } + +void PythonType::supportRepr() + { + table->tp_repr = repr_handler; + } + +void PythonType::supportStr() + { + table->tp_str = str_handler; + } + +void PythonType::supportHash() + { + table->tp_hash = hash_handler; + } + +void PythonType::supportCall() + { + table->tp_call = call_handler; + } + +//-------------------------------------------------------------------------------- +// +// Handlers +// +//-------------------------------------------------------------------------------- +extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->print( fp, flags ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* getattr_handler( PyObject *self, char *name ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->getattr( name ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" int setattr_handler( PyObject *self, char *name, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->setattr( name, Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* getattro_handler( PyObject *self, PyObject *name ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->getattro( Py::Object( name ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" int setattro_handler( PyObject *self, PyObject *name, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->setattro( Py::Object( name ), Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" int compare_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->compare( Py::Object( other ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* repr_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->repr() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* str_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->str() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" long hash_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->hash(); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* call_handler( PyObject *self, PyObject *args, PyObject *kw ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->call( Py::Object( args ), Py::Object( kw ) ) ); + if( kw != NULL ) + return new_reference_to( p->call( Py::Object( args ), Py::Object( kw ) ) ); + else + return new_reference_to( p->call( Py::Object( args ), Py::Object() ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + + +// Sequence methods +extern "C" Py_ssize_t sequence_length_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->sequence_length(); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* sequence_concat_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->sequence_concat( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* sequence_repeat_handler( PyObject *self, Py_ssize_t count ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->sequence_repeat( count ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* sequence_item_handler( PyObject *self, Py_ssize_t index ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->sequence_item( index ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* sequence_slice_handler( PyObject *self, Py_ssize_t first, Py_ssize_t last ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->sequence_slice( first, last ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" int sequence_ass_item_handler( PyObject *self, Py_ssize_t index, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->sequence_ass_item( index, Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" int sequence_ass_slice_handler( PyObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->sequence_ass_slice( first, last, Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +// Mapping +extern "C" Py_ssize_t mapping_length_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->mapping_length(); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* mapping_subscript_handler( PyObject *self, PyObject *key ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->mapping_subscript( Py::Object( key ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" int mapping_ass_subscript_handler( PyObject *self, PyObject *key, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->mapping_ass_subscript( Py::Object( key ), Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +// Number +extern "C" int number_nonzero_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->number_nonzero(); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* number_negative_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_negative() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_positive_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_positive() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_absolute_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_absolute() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_invert_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_invert() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_int_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_int() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_float_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_float() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_long_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_long() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_oct_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_oct() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_hex_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_hex() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_add_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_add( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_subtract_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_subtract( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_multiply_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_multiply( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_divide_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_divide( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_remainder_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_remainder( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_divmod_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_divmod( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_lshift_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_lshift( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_rshift_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_rshift( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_and_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_and( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_xor_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_xor( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_or_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_or( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_power_handler( PyObject *self, PyObject *x1, PyObject *x2 ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return new_reference_to( p->number_power( Py::Object( x1 ), Py::Object( x2 ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +// Buffer +extern "C" Py_ssize_t buffer_getreadbuffer_handler( PyObject *self, Py_ssize_t index, void **pp ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->buffer_getreadbuffer( index, pp ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" Py_ssize_t buffer_getwritebuffer_handler( PyObject *self, Py_ssize_t index, void **pp ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + return p->buffer_getwritebuffer( index, pp ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" Py_ssize_t buffer_getsegcount_handler( PyObject *self, Py_ssize_t *count ) + { + try + { + PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self ); + int i_count = *count; + Py_ssize_t r = p->buffer_getsegcount( &i_count ); + *count = i_count; + return r; + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + + +//================================================================================ +// +// Implementation of PythonExtensionBase +// +//================================================================================ +#define missing_method( method ) \ +throw RuntimeError( "Extension object does not support method " #method ); + +PythonExtensionBase::PythonExtensionBase() + { + } + +PythonExtensionBase::~PythonExtensionBase() + { + assert( ob_refcnt == 0 ); + } + +int PythonExtensionBase::print( FILE *, int ) + { missing_method( print ); return -1; } + +int PythonExtensionBase::setattr( const char*, const Py::Object & ) + { missing_method( setattr ); return -1; } + +Py::Object PythonExtensionBase::getattro( const Py::Object & ) + { missing_method( getattro ); return Py::Nothing(); } + +int PythonExtensionBase::setattro( const Py::Object &, const Py::Object & ) + { missing_method( setattro ); return -1; } + +int PythonExtensionBase::compare( const Py::Object & ) + { missing_method( compare ); return -1; } + +Py::Object PythonExtensionBase::repr() + { missing_method( repr ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::str() + { missing_method( str ); return Py::Nothing(); } + +long PythonExtensionBase::hash() + { missing_method( hash ); return -1; } + +Py::Object PythonExtensionBase::call( const Py::Object &, const Py::Object & ) + { missing_method( call ); return Py::Nothing(); } + + +// Sequence methods +int PythonExtensionBase::sequence_length() + { missing_method( sequence_length ); return -1; } + +Py::Object PythonExtensionBase::sequence_concat( const Py::Object & ) + { missing_method( sequence_concat ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::sequence_repeat( int ) + { missing_method( sequence_repeat ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::sequence_item( int ) + { missing_method( sequence_item ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::sequence_slice( int, int ) + { missing_method( sequence_slice ); return Py::Nothing(); } + +int PythonExtensionBase::sequence_ass_item( int, const Py::Object & ) + { missing_method( sequence_ass_item ); return -1; } + +int PythonExtensionBase::sequence_ass_slice( int, int, const Py::Object & ) + { missing_method( sequence_ass_slice ); return -1; } + + +// Mapping +int PythonExtensionBase::mapping_length() + { missing_method( mapping_length ); return -1; } + +Py::Object PythonExtensionBase::mapping_subscript( const Py::Object & ) + { missing_method( mapping_subscript ); return Py::Nothing(); } + +int PythonExtensionBase::mapping_ass_subscript( const Py::Object &, const Py::Object & ) + { missing_method( mapping_ass_subscript ); return -1; } + + +// Number +int PythonExtensionBase::number_nonzero() + { missing_method( number_nonzero ); return -1; } + +Py::Object PythonExtensionBase::number_negative() + { missing_method( number_negative ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_positive() + { missing_method( number_positive ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_absolute() + { missing_method( number_absolute ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_invert() + { missing_method( number_invert ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_int() + { missing_method( number_int ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_float() + { missing_method( number_float ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_long() + { missing_method( number_long ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_oct() + { missing_method( number_oct ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_hex() + { missing_method( number_hex ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_add( const Py::Object & ) + { missing_method( number_add ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_subtract( const Py::Object & ) + { missing_method( number_subtract ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_multiply( const Py::Object & ) + { missing_method( number_multiply ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_divide( const Py::Object & ) + { missing_method( number_divide ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_remainder( const Py::Object & ) + { missing_method( number_remainder ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_divmod( const Py::Object & ) + { missing_method( number_divmod ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_lshift( const Py::Object & ) + { missing_method( number_lshift ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_rshift( const Py::Object & ) + { missing_method( number_rshift ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_and( const Py::Object & ) + { missing_method( number_and ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_xor( const Py::Object & ) + { missing_method( number_xor ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_or( const Py::Object & ) + { missing_method( number_or ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_power( const Py::Object &, const Py::Object & ) + { missing_method( number_power ); return Py::Nothing(); } + + +// Buffer +int PythonExtensionBase::buffer_getreadbuffer( int, void** ) + { missing_method( buffer_getreadbuffer ); return -1; } + +int PythonExtensionBase::buffer_getwritebuffer( int, void** ) + { missing_method( buffer_getwritebuffer ); return -1; } + +int PythonExtensionBase::buffer_getsegcount( int* ) + { missing_method( buffer_getsegcount ); return -1; } + +//-------------------------------------------------------------------------------- +// +// Method call handlers for +// PythonExtensionBase +// ExtensionModuleBase +// +//-------------------------------------------------------------------------------- + +extern "C" 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(); + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + if( self_as_void == NULL ) + return NULL; + + ExtensionModuleBase *self = static_cast<ExtensionModuleBase *>( self_as_void ); + + String py_name( self_and_name_tuple[1] ); + std::string name( py_name.as_std_string() ); + + Tuple args( _args ); + if( _keywords == NULL ) + { + Dict keywords; // pass an empty dict + + Object result( self->invoke_method_keyword( name, args, keywords ) ); + return new_reference_to( result.ptr() ); + } + else + { + Dict keywords( _keywords ); + + Object result( self->invoke_method_keyword( name, args, keywords ) ); + return new_reference_to( result.ptr() ); + } + } + catch( Exception & ) + { + return 0; + } + } + +extern "C" 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(); + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + if( self_as_void == NULL ) + return NULL; + + ExtensionModuleBase *self = static_cast<ExtensionModuleBase *>( self_as_void ); + + String py_name( self_and_name_tuple[1] ); + std::string name( py_name.as_std_string() ); + + Tuple args( _args ); + + Object result( self->invoke_method_varargs( name, args ) ); + + return new_reference_to( result.ptr() ); + } + catch( Exception & ) + { + return 0; + } + } + +extern "C" void do_not_dealloc( void * ) + {} + + +//-------------------------------------------------------------------------------- +// +// ExtensionExceptionType +// +//-------------------------------------------------------------------------------- +ExtensionExceptionType::ExtensionExceptionType() + : Py::Object() + { + } + +void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::string& name ) + { + std::string module_name( module.fullName() ); + module_name += "."; + module_name += name; + + set( PyErr_NewException( const_cast<char *>( module_name.c_str() ), NULL, NULL ), true ); + } + +ExtensionExceptionType::~ExtensionExceptionType() + { + } + +Exception::Exception( ExtensionExceptionType &exception, const std::string& reason ) + { + PyErr_SetString (exception.ptr(), reason.c_str()); + } + + +} // end of namespace Py diff --git a/lib/kross/python/cxx/cxxextensions.c b/lib/kross/python/cxx/cxxextensions.c new file mode 100644 index 00000000..6f369b2d --- /dev/null +++ b/lib/kross/python/cxx/cxxextensions.c @@ -0,0 +1,19 @@ +/* + Copyright 1998 The Regents of the University of California. + All rights reserved. See Legal.htm for full text and disclaimer. +*/ + +#include "Python.h" +#ifdef __cplusplus +extern "C" { +#endif +PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; +#ifdef __cplusplus +} +#endif + + + + + + diff --git a/lib/kross/python/cxx/cxxsupport.cxx b/lib/kross/python/cxx/cxxsupport.cxx new file mode 100644 index 00000000..61329b60 --- /dev/null +++ b/lib/kross/python/cxx/cxxsupport.cxx @@ -0,0 +1,142 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 1998 The Regents of the University of California. +// All rights reserved. See Legal.htm for full text and disclaimer. +//---------------------------------------------------------------------------// + +#include "Objects.hxx" +namespace Py { + +Py_UNICODE unicode_null_string[1] = { 0 }; + +Type Object::type () const + { + return Type (PyObject_Type (p), true); + } + +String Object::str () const + { + return String (PyObject_Str (p), true); + } + +String Object::repr () const + { + return String (PyObject_Repr (p), true); + } + +std::string Object::as_string() const + { + return static_cast<std::string>(str()); + } + +List Object::dir () const + { + return List (PyObject_Dir (p), true); + } + +bool Object::isType (const Type& t) const + { + return type ().ptr() == t.ptr(); + } + +Char::operator String() const + { + return String(ptr()); + } + +// TMM: non-member operaters for iterators - see above +// I've also made a bug fix in respect to the cxx code +// (dereffed the left.seq and right.seq comparison) +bool operator==(const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.eql( right ); + } + +bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.neq( right ); + } + +bool operator< (const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.lss( right ); + } + +bool operator> (const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.gtr( right ); + } + +bool operator<=(const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.leq( right ); + } + +bool operator>=(const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.geq( right ); + } + +// now for const_iterator +bool operator==(const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.eql( right ); + } + +bool operator!=(const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.neq( right ); + } + +bool operator< (const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.lss( right ); + } + +bool operator> (const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.gtr( right ); + } + +bool operator<=(const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.leq( right ); + } + +bool operator>=(const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.geq( right ); + } + +// For mappings: +bool operator==(const Mapping::iterator& left, const Mapping::iterator& right) + { + return left.eql( right ); + } + +bool operator!=(const Mapping::iterator& left, const Mapping::iterator& right) + { + return left.neq( right ); + } + +// now for const_iterator +bool operator==(const Mapping::const_iterator& left, const Mapping::const_iterator& right) + { + return left.eql( right ); + } + +bool operator!=(const Mapping::const_iterator& left, const Mapping::const_iterator& right) + { + return left.neq( right ); + } + +// TMM: 31May'01 - Added the #ifndef so I can exclude iostreams. +#ifndef CXX_NO_IOSTREAMS +// output + +std::ostream& operator<< (std::ostream& os, const Object& ob) + { + return (os << static_cast<std::string>(ob.str())); + } +#endif + +} // Py |