diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 587d5ee..1941079 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,40 +1,45 @@ project(KROSSPYTHON) -include_directories(${PYTHON2_INCLUDE_DIRS}) +include_directories(${PYTHON2_INCLUDE_DIRS} cxx) kde_enable_exceptions() +add_definitions(-DPYCXX_PYTHON_2TO3) + ########### next target ############### set(libkrosspythoncxx_SRCS - cxx/cxxsupport.cxx - cxx/cxx_extensions.cxx - cxx/cxxextensions.c - cxx/IndirectPythonInterface.cxx + cxx/Src/cxxsupport.cxx + cxx/Src/cxx_extensions.cxx + cxx/Src/cxxextensions.c + cxx/Src/IndirectPythonInterface.cxx + cxx/Src/cxx_exceptions.cxx ) ########### next target ############### set(krosspython_PART_SRCS ${libkrosspythoncxx_SRCS} pythonvariant.cpp pythonextension.cpp pythonmodule.cpp pythonscript.cpp pythoninterpreter.cpp pythonobject.cpp ) add_library(krosspython MODULE ${krosspython_PART_SRCS}) +# the C sources use C99 features +set_property(TARGET krosspython PROPERTY C_STANDARD 11) # -ldl seems to be needed (on Linux at least). # see http://lists.kde.org/?l=koffice-devel&m=116333261328694&w=2 # and http://websvn.kde.org/branches/work/kwin_composite/CMakeLists.txt?rev=603677&r1=603384&r2=603677 target_link_libraries(krosspython KF5::KrossCore Qt5::Gui Qt5::Widgets ${PYTHON2_LIBRARIES} ${CMAKE_DL_LIBS} ) install(TARGETS krosspython DESTINATION ${KDE_INSTALL_PLUGINDIR}) diff --git a/python/cxx/Version.hxx b/python/cxx/CXX/Config.hxx similarity index 86% copy from python/cxx/Version.hxx copy to python/cxx/CXX/Config.hxx index 8286e2f..951d22c 100644 --- a/python/cxx/Version.hxx +++ b/python/cxx/CXX/Config.hxx @@ -1,46 +1,49 @@ //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- +#include "CXX/WrapPython.h" -#ifndef __PyCXX_version_hxx__ -#define __PyCXX_version_hxx__ +#if defined( PYCXX_6_2_COMPATIBILITY ) + typedef int PyCxx_ssize_t; +#else + typedef Py_ssize_t PyCxx_ssize_t; +#endif -#define PYCXX_VERSION_MAJOR 5 -#define PYCXX_VERSION_MINOR 4 -#define PYCXX_VERSION_PATCH 0 -#define PYCXX_MAKEVERSION( major, minor, patch ) ((major<<16)|(minor<<8)|(patch)) -#define PYCXX_VERSION PYCXX_MAKEVERSION( PYCXX_VERSION_MAJOR, PYCXX_VERSION_MINOR, PYCXX_VERSION_PATCH ) +#if PY_MAJOR_VERSION == 2 +#include "CXX/Python2/Config.hxx" +#else +#include "CXX/Python3/Config.hxx" #endif diff --git a/python/cxx/cxxextensions.c b/python/cxx/CXX/CxxDebug.hxx similarity index 89% copy from python/cxx/cxxextensions.c copy to python/cxx/CXX/CxxDebug.hxx index 19eadd9..508395f 100644 --- a/python/cxx/cxxextensions.c +++ b/python/cxx/CXX/CxxDebug.hxx @@ -1,49 +1,41 @@ -/*---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // -//---------------------------------------------------------------------------*/ - -#include "WrapPython.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; - -#ifdef __cplusplus -} +//----------------------------------------------------------------------------- +#if PY_MAJOR_VERSION == 2 +#include "CXX/Python2/CxxDebug.hxx" +#else +#include "CXX/Python3/CxxDebug.hxx" #endif diff --git a/python/cxx/cxxextensions.c b/python/cxx/CXX/Exception.hxx similarity index 89% copy from python/cxx/cxxextensions.c copy to python/cxx/CXX/Exception.hxx index 19eadd9..d4ab4ec 100644 --- a/python/cxx/cxxextensions.c +++ b/python/cxx/CXX/Exception.hxx @@ -1,49 +1,43 @@ -/*---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // -//---------------------------------------------------------------------------*/ +//----------------------------------------------------------------------------- +#include "CXX/WrapPython.h" -#include "WrapPython.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; - -#ifdef __cplusplus -} +#if PY_MAJOR_VERSION == 2 +#include "CXX/Python2/Exception.hxx" +#else +#include "CXX/Python3/Exception.hxx" #endif diff --git a/python/cxx/cxxextensions.c b/python/cxx/CXX/Extensions.hxx similarity index 89% copy from python/cxx/cxxextensions.c copy to python/cxx/CXX/Extensions.hxx index 19eadd9..a4cd266 100644 --- a/python/cxx/cxxextensions.c +++ b/python/cxx/CXX/Extensions.hxx @@ -1,49 +1,43 @@ -/*---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // -//---------------------------------------------------------------------------*/ +//----------------------------------------------------------------------------- +#include "CXX/WrapPython.h" -#include "WrapPython.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; - -#ifdef __cplusplus -} +#if PY_MAJOR_VERSION == 2 +#include "CXX/Python2/Extensions.hxx" +#else +#include "CXX/Python3/Extensions.hxx" #endif diff --git a/python/cxx/CXX/IndirectPythonInterface.hxx b/python/cxx/CXX/IndirectPythonInterface.hxx new file mode 100644 index 0000000..26cd2d2 --- /dev/null +++ b/python/cxx/CXX/IndirectPythonInterface.hxx @@ -0,0 +1,7 @@ +#include "CXX/WrapPython.h" + +#if PY_MAJOR_VERSION == 2 +#include "CXX/Python2/IndirectPythonInterface.hxx" +#else +#include "CXX/Python3/IndirectPythonInterface.hxx" +#endif diff --git a/python/cxx/cxxextensions.c b/python/cxx/CXX/Objects.hxx similarity index 89% copy from python/cxx/cxxextensions.c copy to python/cxx/CXX/Objects.hxx index 19eadd9..cb0294d 100644 --- a/python/cxx/cxxextensions.c +++ b/python/cxx/CXX/Objects.hxx @@ -1,49 +1,43 @@ -/*---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // -//---------------------------------------------------------------------------*/ +//----------------------------------------------------------------------------- +#include "CXX/WrapPython.h" -#include "WrapPython.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; - -#ifdef __cplusplus -} +#if PY_MAJOR_VERSION == 2 +#include "CXX/Python2/Objects.hxx" +#else +#include "CXX/Python3/Objects.hxx" #endif diff --git a/python/cxx/Config.hxx b/python/cxx/CXX/Python2/Config.hxx similarity index 100% rename from python/cxx/Config.hxx rename to python/cxx/CXX/Python2/Config.hxx diff --git a/python/cxx/CXX/Python2/CxxDebug.hxx b/python/cxx/CXX/Python2/CxxDebug.hxx new file mode 100644 index 0000000..b646ffd --- /dev/null +++ b/python/cxx/CXX/Python2/CxxDebug.hxx @@ -0,0 +1,17 @@ +// +// CxxDebug.hxx +// +// Copyright (c) 2008 Barry A. Scott +// +#ifndef __CXX_Debug_hxx +#define __CXX_Debug_hxx + +// +// Functions useful when debugging PyCXX +// +#ifdef PYCXX_DEBUG +extern void bpt(); +extern void printRefCount( PyObject *obj ); +#endif + +#endif diff --git a/python/cxx/CXX/Python2/Exception.hxx b/python/cxx/CXX/Python2/Exception.hxx new file mode 100644 index 0000000..d9d05f9 --- /dev/null +++ b/python/cxx/CXX/Python2/Exception.hxx @@ -0,0 +1,170 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) 1998 - 2007, The Regents of the University of California +// Produced at the Lawrence Livermore National Laboratory +// All rights reserved. +// +// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The +// full copyright notice is contained in the file COPYRIGHT located at the root +// of the PyCXX distribution. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or materials provided with the distribution. +// - Neither the name of the UC/LLNL nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF +// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +//----------------------------------------------------------------------------- + +#ifndef __CXX_Exception_h +#define __CXX_Exception_h + +#include "CXX/WrapPython.h" +#include "CXX/Version.hxx" +#include "CXX/Python2/Config.hxx" +#include "CXX/Python2/CxxDebug.hxx" +#include "CXX/Python2/IndirectPythonInterface.hxx" + +#include +#include + +// This mimics the Python structure, in order to minimize confusion +namespace Py +{ + class ExtensionExceptionType; + + class Object; + + class BaseException + { + public: + BaseException( ExtensionExceptionType &exception, const std::string &reason ); + BaseException( ExtensionExceptionType &exception, Object &reason ); + BaseException( PyObject *exception, Object &reason ); + BaseException( PyObject *exception, const std::string &reason ); + explicit BaseException(); + + void clear(); // clear the error + + // is the exception this specific exception 'exc' + bool matches( ExtensionExceptionType &exc ); + }; + +#if defined( PYCXX_6_2_COMPATIBILITY ) + class Exception : public BaseException + { + public: + Exception( ExtensionExceptionType &exception, const std::string &reason ) + : BaseException( exception, reason ) + {} + + Exception( ExtensionExceptionType &exception, Object &reason ) + : BaseException( exception, reason ) + {} + + Exception( PyObject *exception, Object &reason ) + : BaseException ( exception, reason ) + {} + + Exception( PyObject *exception, const std::string &reason ) + : BaseException( exception, reason ) + {} + + explicit Exception() + : BaseException() + {} + }; +#endif + + // for user defined exceptions to be made know to pycxx + typedef void (*throw_exception_func_t)( void ); + void addPythonException( ExtensionExceptionType &py_exc_type, throw_exception_func_t throw_func ); + +#define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ + class eclass : public bclass \ + { \ + public: \ + eclass() {} \ + eclass( const char *reason ) { PyErr_SetString( _Exc_##eclass(), reason ); } \ + eclass( const std::string &reason ) { PyErr_SetString( _Exc_##eclass(), reason.c_str() ); } \ + ~eclass() {} \ + \ + static void throwFunc() { throw eclass(); } \ + static PyObject *exceptionType() { return _Exc_##eclass(); } \ + }; \ + +#include + +#undef PYCXX_STANDARD_EXCEPTION + +#define PYCXX_USER_EXCEPTION_STR_ARG( uclass ) \ +class uclass : public Py::BaseException \ +{ \ +public: \ + uclass( const std::string &reason ) \ + : Py::BaseException( m_error, reason ) \ + { } \ + ~uclass() {} \ + static void init( Py::ExtensionModuleBase &module ) \ + { \ + m_error.init( module, #uclass ); \ + Py::addPythonException( m_error, throwFunc ); \ + Py::Dict d( module.moduleDictionary() ); \ + d[#uclass] = m_error; \ + } \ +private: \ + uclass() : Py::BaseException() {} \ + static void throwFunc() \ + { \ + throw uclass(); \ + } \ + static Py::ExtensionExceptionType m_error; \ +}; \ +Py::ExtensionExceptionType uclass::m_error; + +#define PYCXX_USER_EXCEPTION_NO_ARG( uclass ) \ +class uclass : public Py::BaseException \ +{ \ +public: \ + uclass() \ + : Py::BaseException() \ + { } \ + ~uclass() {} \ + static void init( Py::ExtensionModuleBase &module ) \ + { \ + m_error.init( module, #uclass ); \ + Py::addPythonException( m_error, throwFunc ); \ + Py::Dict d( module.moduleDictionary() ); \ + d[#uclass] = m_error; \ + } \ +private: \ + static void throwFunc() \ + { \ + throw uclass(); \ + } \ + static Py::ExtensionExceptionType m_error; \ +}; \ +Py::ExtensionExceptionType uclass::m_error; + +}// Py + +#endif diff --git a/python/cxx/CXX/Python2/ExtensionModule.hxx b/python/cxx/CXX/Python2/ExtensionModule.hxx new file mode 100644 index 0000000..5f59dc0 --- /dev/null +++ b/python/cxx/CXX/Python2/ExtensionModule.hxx @@ -0,0 +1,207 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) 1998 - 2007, The Regents of the University of California +// Produced at the Lawrence Livermore National Laboratory +// All rights reserved. +// +// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The +// full copyright notice is contained in the file COPYRIGHT located at the root +// of the PyCXX distribution. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or materials provided with the distribution. +// - Neither the name of the UC/LLNL nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF +// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +//----------------------------------------------------------------------------- + +#ifndef __CXX_ExtensionModule__h +#define __CXX_ExtensionModule__h + +namespace Py +{ + 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_noargs( void *method_def ) = 0; + virtual Object invoke_method_keyword( void *method_def, const Tuple &_args, const Dict &_keywords ) = 0; + virtual Object invoke_method_varargs( void *method_def, const Tuple &_args ) = 0; + + const std::string &name() const; + const std::string &fullName() const; + + // what is returned from PyInit_ function + Object moduleObject( void ) const; + + protected: + // Initialize the module + void initialize( const char *module_doc ); + + const std::string m_module_name; + const std::string m_full_module_name; + MethodTable m_method_table; + PyObject *m_module; + + private: + // + // prevent the compiler generating these unwanted functions + // + ExtensionModuleBase( const ExtensionModuleBase & ); //unimplemented + void operator=( const ExtensionModuleBase & ); //unimplemented + }; + + // Note: Python calls noargs as varargs buts args==NULL + extern "C" PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ); + extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ); + extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ); + + extern "C" void do_not_dealloc( void * ); + + template + class ExtensionModule : public ExtensionModuleBase + { + public: + ExtensionModule( const char *name ) + : ExtensionModuleBase( name ) + {} + virtual ~ExtensionModule() + {} + + protected: + typedef Object (T::*method_noargs_function_t)(); + 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 *> method_map_t; + + static void add_noargs_method( const char *name, method_noargs_function_t function, const char *doc="" ) + { + method_map_t &mm = methods(); + mm[ std::string( name ) ] = new MethodDefExt( name, function, method_noargs_call_handler, doc ); + } + + static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) + { + method_map_t &mm = methods(); + mm[ std::string( name ) ] = new MethodDefExt( name, function, method_varargs_call_handler, doc ); + } + + static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) + { + method_map_t &mm = methods(); + mm[ std::string( name ) ] = new MethodDefExt( name, function, method_keyword_call_handler, doc ); + } + + void initialize( const char *module_doc="" ) + { + ExtensionModuleBase::initialize( module_doc ); + Dict dict( moduleDictionary() ); + + // + // put each of the methods into the modules dictionary + // so that we get called back at the function in T. + // + method_map_t &mm = methods(); + EXPLICIT_TYPENAME method_map_t::const_iterator i = mm.begin(); + EXPLICIT_TYPENAME method_map_t::const_iterator i_end = mm.end(); + for ( ; i != i_end; ++i ) + { + MethodDefExt *method_def = (*i).second; + + static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); + + Tuple args( 2 ); + args[0] = Object( self, true ); + args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); + + assert( m_module != NULL ); + PyObject *func = PyCFunction_NewEx + ( + &method_def->ext_meth_def, + new_reference_to( args ), + m_module + ); + + method_def->py_method = Object( func, true ); + + dict[ (*i).first ] = method_def->py_method; + } + } + + 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_noargs( void *method_def ) + { + // cast up to the derived class, method_def and call + T *self = static_cast( this ); + MethodDefExt *meth_def = reinterpret_cast *>( method_def ); + + return (self->*meth_def->ext_noargs_function)(); + } + + // this invoke function must be called from within a try catch block + virtual Object invoke_method_varargs( void *method_def, const Tuple &args ) + { + // cast up to the derived class, method_def and call + T *self = static_cast( this ); + MethodDefExt *meth_def = reinterpret_cast *>( method_def ); + + return (self->*meth_def->ext_varargs_function)( args ); + } + + // this invoke function must be called from within a try catch block + virtual Object invoke_method_keyword( void *method_def, const Tuple &args, const Dict &keywords ) + { + // cast up to the derived class, method_def and call + T *self = static_cast( this ); + MethodDefExt *meth_def = reinterpret_cast *>( method_def ); + + return (self->*meth_def->ext_keyword_function)( args, keywords ); + } + + private: + // + // prevent the compiler generating these unwanted functions + // + ExtensionModule( const ExtensionModule & ); //unimplemented + void operator=( const ExtensionModule & ); //unimplemented + }; +} // Namespace Py + + +// End of __CXX_ExtensionModule__h +#endif diff --git a/python/cxx/CXX/Python2/ExtensionOldType.hxx b/python/cxx/CXX/Python2/ExtensionOldType.hxx new file mode 100644 index 0000000..570e31f --- /dev/null +++ b/python/cxx/CXX/Python2/ExtensionOldType.hxx @@ -0,0 +1,397 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) 1998 - 2007, The Regents of the University of California +// Produced at the Lawrence Livermore National Laboratory +// All rights reserved. +// +// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The +// full copyright notice is contained in the file COPYRIGHT located at the root +// of the PyCXX distribution. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or materials provided with the distribution. +// - Neither the name of the UC/LLNL nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF +// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +//----------------------------------------------------------------------------- + +#ifndef __CXX_ExtensionOldType__h +#define __CXX_ExtensionOldType__h + +namespace Py +{ + template class PythonExtension + : public PythonExtensionBase + { + public: + static PyTypeObject *type_object() + { + return behaviors().type_object(); + } + + static bool check( PyObject *p ) + { + // is p like me? + return p->ob_type == type_object(); + } + + static bool 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 ); + } + + PyObject *selfPtr() + { + return this; + } + + Object self() + { + return asObject( this ); + } + + protected: + explicit PythonExtension() + : PythonExtensionBase() + { + PyObject_Init( this, type_object() ); + + // every object must support getattr + behaviors().supportGetattr(); + } + + virtual ~PythonExtension() + {} + + static PythonType &behaviors() + { + static PythonType* p; + if( p == NULL ) + { +#if defined( _CPPRTTI ) || defined( __GNUG__ ) + const char *default_name =( typeid( T ) ).name(); +#else + const char *default_name = "unknown"; +#endif + p = new PythonType( sizeof( T ), 0, default_name ); + p->set_tp_dealloc( extension_object_deallocator ); + } + + return *p; + } + + typedef Object (T::*method_noargs_function_t)(); + 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 *> 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 ); + } + + if( name == "__doc__" && type_object()->tp_doc != NULL ) + { + return Py::String( type_object()->tp_doc ); + } + +// trying to fake out being a class for help() +// else if( name == "__bases__" ) +// { +// return Py::Tuple( 0 ); +// } +// else if( name == "__module__" ) +// { +// return Py::Nothing(); +// } +// else if( name == "__dict__" ) +// { +// return Py::Dict(); +// } + + return getattr_methods( _name ); + } + + // turn a name into function object + virtual Object getattr_methods( const char *_name ) + { + std::string name( _name ); + + method_map_t &mm = methods(); + + // see if name exists and get entry with method + EXPLICIT_TYPENAME method_map_t::const_iterator i = mm.find( name ); + if( i == mm.end() ) + { + if( name == "__methods__" ) + { + List methods; + + i = mm.begin(); + EXPLICIT_TYPENAME method_map_t::const_iterator i_end = mm.end(); + + for( ; i != i_end; ++i ) + methods.append( String( (*i).first ) ); + + return methods; + } + + throw AttributeError( name ); + } + + MethodDefExt *method_def = i->second; + + Tuple self( 2 ); + + self[0] = Object( this ); + self[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); + + PyObject *func = PyCFunction_NewEx( &method_def->ext_meth_def, self.ptr(), NULL ); + + return Object(func, true); + } + + // check that all methods added are unique + static void check_unique_method_name( const char *name ) + { + method_map_t &mm = methods(); + EXPLICIT_TYPENAME method_map_t::const_iterator i; + i = mm.find( name ); + if( i != mm.end() ) + throw AttributeError( name ); + } + + static void add_noargs_method( const char *name, method_noargs_function_t function, const char *doc="" ) + { + check_unique_method_name( name ); + method_map_t &mm = methods(); + mm[ std::string( name ) ] = new MethodDefExt( name, function, method_noargs_call_handler, doc ); + } + + static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) + { + check_unique_method_name( name ); + method_map_t &mm = methods(); + mm[ std::string( name ) ] = new MethodDefExt( name, function, method_varargs_call_handler, doc ); + } + + static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) + { + check_unique_method_name( name ); + method_map_t &mm = methods(); + mm[ std::string( name ) ] = new MethodDefExt( name, function, method_keyword_call_handler, doc ); + } + + 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; + } + + // Note: Python calls noargs as varargs buts args==NULL + static PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ) + { + try + { + Tuple self_and_name_tuple( _self_and_name_tuple ); + + PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); + T *self = static_cast( self_in_cobject ); + MethodDefExt *meth_def = reinterpret_cast *>( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); + Object result; + + // Adding try & catch in case of STL debug-mode exceptions. + #ifdef _STLP_DEBUG + try + { + result = (self->*meth_def->ext_noargs_function)(); + } + catch( std::__stl_debug_exception ) + { + // throw cxx::RuntimeError( sErrMsg ); + throw RuntimeError( "Error message not set yet." ); + } + #else + result = (self->*meth_def->ext_noargs_function)(); + #endif // _STLP_DEBUG + + return new_reference_to( result.ptr() ); + } + catch( BaseException & ) + { + 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( self_in_cobject ); + + MethodDefExt *meth_def = reinterpret_cast *>( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); + Tuple args( _args ); + + Object result; + + // 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 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( BaseException & ) + { + return 0; + } + } + + 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( self_in_cobject ); + + MethodDefExt *meth_def = reinterpret_cast *>( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); + + 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( BaseException & ) + { + return 0; + } + } + + static void extension_object_deallocator( PyObject* t ) + { + delete (T *)( t ); + } + + // + // prevent the compiler generating these unwanted functions + // + explicit PythonExtension( const PythonExtension &other ); + void operator=( const PythonExtension &rhs ); + }; + + // + // ExtensionObject is an Object that will accept only T's. + // + template + class ExtensionObject: public Object + { + public: + + explicit ExtensionObject( PyObject *pyob ) + : Object( pyob ) + { + validate(); + } + + ExtensionObject( const ExtensionObject &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 ) + 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( ptr() ); + } + }; +} // Namespace Py + +// End of __CXX_ExtensionOldType__h +#endif diff --git a/python/cxx/CXX/Python2/ExtensionType.hxx b/python/cxx/CXX/Python2/ExtensionType.hxx new file mode 100644 index 0000000..7145bd0 --- /dev/null +++ b/python/cxx/CXX/Python2/ExtensionType.hxx @@ -0,0 +1,418 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) 1998 - 2007, The Regents of the University of California +// Produced at the Lawrence Livermore National Laboratory +// All rights reserved. +// +// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The +// full copyright notice is contained in the file COPYRIGHT located at the root +// of the PyCXX distribution. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or materials provided with the distribution. +// - Neither the name of the UC/LLNL nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF +// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +//----------------------------------------------------------------------------- + +#ifndef __CXX_ExtensionClass__h +#define __CXX_ExtensionClass__h + +#define PYCXX_NOARGS_METHOD_NAME( NAME ) _callNoArgsMethod__##NAME +#define PYCXX_VARARGS_METHOD_NAME( NAME ) _callVarArgsMethod__##NAME +#define PYCXX_KEYWORDS_METHOD_NAME( NAME ) _callKeywordsMethod__##NAME + +#define PYCXX_NOARGS_METHOD_DECL( CLS, NAME ) \ + static PyObject *PYCXX_NOARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *, PyObject * ) \ + { \ + try \ + { \ + Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ + CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ + Py::Object r( (self->NAME)() ); \ + return Py::new_reference_to( r.ptr() ); \ + } \ + catch( Py::BaseException & ) \ + { \ + return 0; \ + } \ + } +#define PYCXX_VARARGS_METHOD_DECL( CLS, NAME ) \ + static PyObject *PYCXX_VARARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject * ) \ + { \ + try \ + { \ + Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ + CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ + Py::Tuple a( _a ); \ + Py::Object r( (self->NAME)( a ) ); \ + return Py::new_reference_to( r.ptr() ); \ + } \ + catch( Py::BaseException & ) \ + { \ + return 0; \ + } \ + } +#define PYCXX_KEYWORDS_METHOD_DECL( CLS, NAME ) \ + static PyObject *PYCXX_KEYWORDS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject *_k ) \ + { \ + try \ + { \ + Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ + CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ + Py::Tuple a( _a ); \ + Py::Dict k; \ + if( _k != NULL ) \ + k = _k; \ + Py::Object r( (self->NAME)( a, k ) ); \ + return Py::new_reference_to( r.ptr() ); \ + } \ + catch( Py::BaseException & ) \ + { \ + return 0; \ + } \ + } + +// need to support METH_STATIC and METH_CLASS + +#define PYCXX_ADD_NOARGS_METHOD( PYNAME, NAME, docs ) \ + add_method( #PYNAME, (PyCFunction)PYCXX_NOARGS_METHOD_NAME( NAME ), METH_NOARGS, docs ) +#define PYCXX_ADD_VARARGS_METHOD( PYNAME, NAME, docs ) \ + add_method( #PYNAME, (PyCFunction)PYCXX_VARARGS_METHOD_NAME( NAME ), METH_VARARGS, docs ) +#define PYCXX_ADD_KEYWORDS_METHOD( PYNAME, NAME, docs ) \ + add_method( #PYNAME, (PyCFunction)PYCXX_KEYWORDS_METHOD_NAME( NAME ), METH_VARARGS | METH_KEYWORDS, docs ) + +namespace Py +{ + extern PythonExtensionBase *getPythonExtensionBase( PyObject *self ); + + struct PythonClassInstance + { + PyObject_HEAD + PythonExtensionBase *m_pycxx_object; + }; + + class ExtensionClassMethodsTable + { + public: + ExtensionClassMethodsTable() + : m_methods_table( new PyMethodDef[ METHOD_TABLE_SIZE_INCREMENT ] ) + , m_methods_used( 0 ) + , m_methods_size( METHOD_TABLE_SIZE_INCREMENT ) + { + // add the sentinel marking the table end + PyMethodDef *p = &m_methods_table[ 0 ]; + + p->ml_name = NULL; + p->ml_meth = NULL; + p->ml_flags = 0; + p->ml_doc = NULL; + } + + ~ExtensionClassMethodsTable() + { + delete[] m_methods_table; + } + + // check that all methods added are unique + void check_unique_method_name( const char *_name ) + { + std::string name( _name ); + for( int i=0; iml_name = const_cast( name ); + p->ml_meth = function; + p->ml_flags = flags; + p->ml_doc = const_cast( doc ); + + m_methods_used++; + p++; + + // add the sentinel marking the table end + p->ml_name = NULL; + p->ml_meth = NULL; + p->ml_flags = 0; + p->ml_doc = NULL; + + return m_methods_table; + } + + private: + enum {METHOD_TABLE_SIZE_INCREMENT = 1}; + PyMethodDef *m_methods_table; + int m_methods_used; + int m_methods_size; + }; + + template class PythonClass + : public PythonExtensionBase + { + protected: + explicit PythonClass( PythonClassInstance *self, Tuple &/*args*/, Dict &/*kwds*/ ) + : PythonExtensionBase() + , m_class_instance( self ) + { + } + + virtual ~PythonClass() + {} + + static ExtensionClassMethodsTable &methodTable() + { + static ExtensionClassMethodsTable *method_table; + if( method_table == NULL ) + method_table = new ExtensionClassMethodsTable; + return *method_table; + } + + static void add_method( const char *name, PyCFunction function, int flags, const char *doc=NULL ) + { + behaviors().set_methods( methodTable().add_method( name, function, flags, doc ) ); + } + + static PythonType &behaviors() + { + static PythonType *p; + if( p == NULL ) + { +#if defined( _CPPRTTI ) || defined( __GNUG__ ) + const char *default_name = (typeid( T )).name(); +#else + const char *default_name = "unknown"; +#endif + p = new PythonType( sizeof( PythonClassInstance ), 0, default_name ); + p->set_tp_new( extension_object_new ); + p->set_tp_init( extension_object_init ); + p->set_tp_dealloc( extension_object_deallocator ); + // we are a class + p->supportClass(); + + // always support get and set attr + p->supportGetattro(); + p->supportSetattro(); + } + + return *p; + } + + static PyObject *extension_object_new( PyTypeObject *subtype, PyObject * /*args*/, PyObject * /*kwds*/ ) + { +#ifdef PYCXX_DEBUG + std::cout << "extension_object_new()" << std::endl; +#endif + PythonClassInstance *o = reinterpret_cast( subtype->tp_alloc( subtype, 0 ) ); + if( o == NULL ) + return NULL; + + o->m_pycxx_object = NULL; + + PyObject *self = reinterpret_cast( o ); +#ifdef PYCXX_DEBUG + std::cout << "extension_object_new() => self=0x" << std::hex << reinterpret_cast< unsigned long >( self ) << std::dec << std::endl; +#endif + return self; + } + + static int extension_object_init( PyObject *_self, PyObject *args_, PyObject *kwds_ ) + { + try + { + Py::Tuple args( args_ ); + Py::Dict kwds; + if( kwds_ != NULL ) + kwds = kwds_; + + PythonClassInstance *self = reinterpret_cast( _self ); +#ifdef PYCXX_DEBUG + std::cout << "extension_object_init( self=0x" << std::hex << reinterpret_cast< unsigned long >( self ) << std::dec << " )" << std::endl; + std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; +#endif + + if( self->m_pycxx_object == NULL ) + { + self->m_pycxx_object = new T( self, args, kwds ); +#ifdef PYCXX_DEBUG + std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; +#endif + } + else + { +#ifdef PYCXX_DEBUG + std::cout << " reinit - self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; +#endif + self->m_pycxx_object->reinit( args, kwds ); + } + } + catch( BaseException & ) + { + return -1; + } + return 0; + } + + static void extension_object_deallocator( PyObject *_self ) + { + PythonClassInstance *self = reinterpret_cast< PythonClassInstance * >( _self ); +#ifdef PYCXX_DEBUG + std::cout << "extension_object_deallocator( self=0x" << std::hex << reinterpret_cast< unsigned long >( self ) << std::dec << " )" << std::endl; + std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; +#endif + delete self->m_pycxx_object; + _self->ob_type->tp_free( _self ); + } + + public: + static PyTypeObject *type_object() + { + return behaviors().type_object(); + } + + static Object type() + { + return Object( reinterpret_cast( behaviors().type_object() ) ); + } + + static bool check( PyObject *p ) + { + // is p a me or a derived me + switch( PyObject_IsInstance( p, reinterpret_cast( type_object() ) ) ) + { + default: + case -1: + throw Exception(); + case 0: + return false; + case 1: + return true; + } + } + + static bool check( const Object &ob ) + { + return check( ob.ptr() ); + } + + virtual PyObject *selfPtr() + { + return reinterpret_cast( m_class_instance ); + } + + virtual Object self() + { + return Object( reinterpret_cast( m_class_instance ) ); + } + + protected: + private: + PythonClassInstance *m_class_instance; + + private: + // + // prevent the compiler generating these unwanted functions + // + explicit PythonClass( const PythonClass &other ); + void operator=( const PythonClass &rhs ); + }; + + // + // ExtensionObject is an Object that will accept only T's. + // + template + class PythonClassObject: public Object + { + public: + + explicit PythonClassObject( PyObject *pyob ) + : Object( pyob ) + { + validate(); + } + + PythonClassObject( const PythonClassObject &other ) + : Object( *other ) + { + validate(); + } + + PythonClassObject( const Object &other ) + : Object( *other ) + { + validate(); + } + + PythonClassObject &operator=( const Object &rhs ) + { + *this = *rhs; + return *this; + } + + PythonClassObject &operator=( PyObject *rhsp ) + { + if( ptr() != rhsp ) + set( rhsp ); + return *this; + } + + virtual bool accepts( PyObject *pyob ) const + { + return( pyob && T::check( pyob ) ); + } + + // + // Obtain a pointer to the PythonExtension object + // + T *getCxxObject( void ) + { + return dynamic_cast< T * >( getPythonExtensionBase( ptr() ) ); + } + }; +} // Namespace Py + +// End of __CXX_ExtensionClass__h +#endif diff --git a/python/cxx/CXX/Python2/ExtensionTypeBase.hxx b/python/cxx/CXX/Python2/ExtensionTypeBase.hxx new file mode 100644 index 0000000..237ae78 --- /dev/null +++ b/python/cxx/CXX/Python2/ExtensionTypeBase.hxx @@ -0,0 +1,181 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) 1998 - 2007, The Regents of the University of California +// Produced at the Lawrence Livermore National Laboratory +// All rights reserved. +// +// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The +// full copyright notice is contained in the file COPYRIGHT located at the root +// of the PyCXX distribution. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or materials provided with the distribution. +// - Neither the name of the UC/LLNL nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF +// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +//----------------------------------------------------------------------------- + +#ifndef __CXX_ExtensionTypeBase__h +#define __CXX_ExtensionTypeBase__h + +namespace Py +{ + // 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: + // object + virtual void reinit( Tuple &args, Dict &kwds ); + + // object basics + virtual int print( FILE *, int ); + virtual Object getattr( const char * ); + virtual int setattr( const char *, const Object & ); + virtual Object getattro( const String & ); + Object genericGetAttro( const String & ); + virtual int setattro( const String &, const Object & ); + int genericSetAttro( const String &, const Object & ); + virtual int compare( const Object & ); + virtual Object rich_compare( const Object &, int ); + virtual Object repr(); + virtual Object str(); + virtual long hash(); + virtual Object call( const Object &, const Object & ); + virtual Object iter(); + virtual PyObject *iternext(); + + // Sequence methods + virtual PyCxx_ssize_t sequence_length(); + virtual Object sequence_concat( const Object & ); + virtual Object sequence_repeat( Py_ssize_t ); + virtual Object sequence_item( Py_ssize_t ); + virtual Object sequence_slice( Py_ssize_t, Py_ssize_t ); + + virtual int sequence_ass_item( Py_ssize_t, const Object & ); + virtual int sequence_ass_slice( Py_ssize_t, Py_ssize_t, const Object & ); + + virtual Object sequence_inplace_concat( const Object & ); + virtual Object sequence_inplace_repeat( Py_ssize_t ); + + virtual int sequence_contains( const Object & ); + + // Mapping + virtual PyCxx_ssize_t mapping_length(); + virtual Object mapping_subscript( const Object & ); + virtual int mapping_ass_subscript( const Object &, const Object & ); + + // Number + virtual int number_nonzero(); + virtual Object number_negative(); + virtual Object number_positive(); + virtual Object number_absolute(); + virtual Object number_invert(); + virtual Object number_int(); + virtual Object number_float(); + virtual Object number_long(); + virtual Object number_oct(); + virtual Object number_hex(); + virtual Object number_add( const Object & ); + virtual Object number_subtract( const Object & ); + virtual Object number_multiply( const Object & ); + virtual Object number_divide( const Object & ); + virtual Object number_remainder( const Object & ); + virtual Object number_divmod( const Object & ); + virtual Object number_lshift( const Object & ); + virtual Object number_rshift( const Object & ); + virtual Object number_and( const Object & ); + virtual Object number_xor( const Object & ); + virtual Object number_or( const Object & ); + virtual Object number_power( const Object &, const Object & ); + + // Buffer + virtual Py_ssize_t buffer_getreadbuffer( Py_ssize_t, void** ); + virtual Py_ssize_t buffer_getwritebuffer( Py_ssize_t, void** ); + virtual Py_ssize_t buffer_getsegcount( Py_ssize_t* ); + + public: + // helper functions to call function fn_name with 0 to 9 args + Object callOnSelf( const std::string &fn_name ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7, const Object &arg8 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7, const Object &arg8, const Object &arg9 ); + + public: + virtual PyObject *selfPtr() = 0; + virtual Object self() = 0; + + private: + void missing_method( void ); + static PyObject *method_call_handler( PyObject *self, PyObject *args ); + }; + +} // Namespace Py + +// End of __CXX_ExtensionTypeBase__h +#endif diff --git a/python/cxx/CXX/Python2/Extensions.hxx b/python/cxx/CXX/Python2/Extensions.hxx new file mode 100644 index 0000000..1b0f8f3 --- /dev/null +++ b/python/cxx/CXX/Python2/Extensions.hxx @@ -0,0 +1,189 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) 1998 - 2007, The Regents of the University of California +// Produced at the Lawrence Livermore National Laboratory +// All rights reserved. +// +// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The +// full copyright notice is contained in the file COPYRIGHT located at the root +// of the PyCXX distribution. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or materials provided with the distribution. +// - Neither the name of the UC/LLNL nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF +// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +//----------------------------------------------------------------------------- + +#ifndef __CXX_Extensions__h +#define __CXX_Extensions__h + + +#ifdef _MSC_VER +// disable warning C4786: symbol greater than 255 character, +// okay to ignore +#pragma warning( disable: 4786 ) +#endif + +#include "CXX/WrapPython.h" +#include "CXX/Version.hxx" +#include "CXX/Python2/Config.hxx" +#include "CXX/Python2/CxxDebug.hxx" +#include "CXX/Python2/Objects.hxx" + +extern "C" { extern PyObject py_object_initializer; } + +#include +#include + +// ---------------------------------------------------------------------- + +namespace Py +{ + class ExtensionModuleBase; + + // Make an Exception Type for use in raising custom exceptions + class ExtensionExceptionType : public Object + { + public: + ExtensionExceptionType(); + virtual ~ExtensionExceptionType(); + + // call init to create the type + void init( ExtensionModuleBase &module, const std::string &name, ExtensionExceptionType &parent ); + void init( ExtensionModuleBase &module, const std::string &name ); + }; + + class MethodTable + { + public: + MethodTable(); + virtual ~MethodTable(); + + void add( const char *method_name, PyCFunction f, const char *doc="", int flag=1 ); + PyMethodDef *table(); + + protected: + std::vector 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 + + // Note: Python calls noargs as varargs buts args==NULL + extern "C" typedef PyObject *(*method_noargs_call_handler_t)( PyObject *_self, PyObject * ); + extern "C" typedef PyObject *(*method_varargs_call_handler_t)( PyObject *_self, PyObject *_args ); + extern "C" typedef PyObject *(*method_keyword_call_handler_t)( PyObject *_self, PyObject *_args, PyObject *_dict ); + + template + class MethodDefExt + { + public: + typedef Object (T::*method_noargs_function_t)(); + typedef Object (T::*method_varargs_function_t)( const Tuple &args ); + typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); + + // NOARGS + MethodDefExt + ( + const char *_name, + method_noargs_function_t _function, + method_noargs_call_handler_t _handler, + const char *_doc + ) + { + ext_meth_def.ml_name = const_cast( _name ); + ext_meth_def.ml_meth = reinterpret_cast( _handler ); + ext_meth_def.ml_flags = METH_NOARGS; + ext_meth_def.ml_doc = const_cast( _doc ); + + ext_noargs_function = _function; + ext_varargs_function = NULL; + ext_keyword_function = NULL; + } + + // VARARGS + 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( _name ); + ext_meth_def.ml_meth = reinterpret_cast( _handler ); + ext_meth_def.ml_flags = METH_VARARGS; + ext_meth_def.ml_doc = const_cast( _doc ); + + ext_noargs_function = NULL; + ext_varargs_function = _function; + ext_keyword_function = NULL; + } + + // VARARGS + KEYWORD + 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( _name ); + ext_meth_def.ml_meth = reinterpret_cast( _handler ); + ext_meth_def.ml_flags = METH_VARARGS|METH_KEYWORDS; + ext_meth_def.ml_doc = const_cast( _doc ); + + ext_noargs_function = NULL; + ext_varargs_function = NULL; + ext_keyword_function = _function; + } + + ~MethodDefExt() + {} + + PyMethodDef ext_meth_def; + method_noargs_function_t ext_noargs_function; + method_varargs_function_t ext_varargs_function; + method_keyword_function_t ext_keyword_function; + Object py_method; + }; +} // Namespace Py + +#include "CXX/Python2/ExtensionModule.hxx" +#include "CXX/Python2/PythonType.hxx" +#include "CXX/Python2/ExtensionTypeBase.hxx" +#include "CXX/Python2/ExtensionOldType.hxx" +#include "CXX/Python2/ExtensionType.hxx" + +// End of CXX_Extensions.h +#endif diff --git a/python/cxx/IndirectPythonInterface.hxx b/python/cxx/CXX/Python2/IndirectPythonInterface.hxx similarity index 78% rename from python/cxx/IndirectPythonInterface.hxx rename to python/cxx/CXX/Python2/IndirectPythonInterface.hxx index 90fdc25..ba74194 100644 --- a/python/cxx/IndirectPythonInterface.hxx +++ b/python/cxx/CXX/Python2/IndirectPythonInterface.hxx @@ -1,193 +1,161 @@ //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ #define __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ -#include "WrapPython.h" +#include "CXX/WrapPython.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_BaseException(); -PyObject * _Exc_MemoryErrorInst(); +#define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ + PyObject * _Exc_##eclass(); -#if PY_MAJOR_VERSION >= 2 -PyObject * _Exc_IndentationError(); -PyObject * _Exc_TabError(); -PyObject * _Exc_UnboundLocalError(); -PyObject * _Exc_UnicodeError(); -#endif +#include "CXX/Python2/cxx_standard_exceptions.hxx" +#undef PYCXX_STANDARD_EXCEPTION // // Wrap Object variables as function calls // PyObject * _None(); +PyObject * _False(); +PyObject * _True(); // // 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 * _Bool_Type(); +bool _Boolean_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 ); +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) char *__Py_PackageContext(); +#endif } #endif // __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ diff --git a/python/cxx/Objects.hxx b/python/cxx/CXX/Python2/Objects.hxx similarity index 73% rename from python/cxx/Objects.hxx rename to python/cxx/CXX/Python2/Objects.hxx index 0ecbe1d..e453fcd 100644 --- a/python/cxx/Objects.hxx +++ b/python/cxx/CXX/Python2/Objects.hxx @@ -1,3034 +1,3629 @@ //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_Objects__h #define __CXX_Objects__h -#include "WrapPython.h" -#include "Version.hxx" -#include "Config.hxx" -#include "Exception.hxx" +#include "CXX/WrapPython.h" +#include "CXX/Version.hxx" +#include "CXX/Config.hxx" +#include "CXX/Exception.hxx" #include #include STR_STREAM #include #include #include #include #include + namespace Py { - typedef int sequence_index_type; // type of an index into a sequence + void ifPyErrorThrowCxxException(); + + typedef PyCxx_ssize_t sequence_index_type; // type of an index into a sequence // Forward declarations class Object; class Type; template class SeqBase; class String; class List; template class MapBase; + class Tuple; + class Dict; // 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(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 or MapBase. // 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(); -} + validate(); + } MyType(const Object& other): Object(other.ptr()) { - validate(); -} + validate(); + } */ // Alernate version for the constructor to allow for construction from owned pointers: /* - explicit MyType (PyObject *pyob): Object(pyob) { - validate(); -} + 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); -} + return (*this = *rhs); + } Mytype& operator= (PyObject* rhsp) { - if(ptr() == rhsp) return *this; - set(rhsp); - return *this; -} + 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 to define an object // note that it contains PythonExtension::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)) - { - std::string err("CXX : Error creating object of type "); - PyObject* ps = PyObject_Repr(p); - err += PyString_AsString(ps); - Py::_XDECREF(ps); - - release (); - if(PyErr_Occurred()) - { // Error message already set - throw Exception(); - } - - // Better error message if RTTI available -#if defined( _CPPRTTI ) || defined(__GNUG__) - err += " ["; - err += (typeid (*this)).name(); - err += "]"; -#endif - - throw TypeError (err); - } - } + void validate(); public: // Constructor acquires new ownership of pointer unless explicitly told not to. - explicit Object (PyObject* pyob=Py::_None(), bool owned = false): p (pyob) + 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) + 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."); + throw RuntimeError("Object::decrement_reference_count error."); Py::_XDECREF(p); } + // Would like to call this pointer() but messes up STL in SeqBase PyObject* ptr () const { return p; } // // Queries // // Can pyob be used in this object's constructor? - virtual bool accepts (PyObject *pyob) const + virtual bool accepts (PyObject *) const { - return (pyob != 0); + // allow any object or NULL + return true; } Py_ssize_t 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(s.c_str())) ? true: false; } Object getAttr (const std::string& s) const { return Object (PyObject_GetAttrString (p, const_cast(s.c_str())), true); } + Object callMemberFunction( const std::string& function_name ) const; + Object callMemberFunction( const std::string& function_name, const Tuple &args ) const; + Object callMemberFunction( const std::string& function_name, const Tuple &args, const Dict &kw ) const; + 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); - //} - // + // convert to bool + bool as_bool() const + { + return PyObject_IsTrue( ptr() ) != 0; + } + bool is(PyObject *pother) const { // identity test return p == pother; } bool is(const Object& other) const { // identity test return p == other.p; } + bool isNull() const + { + return p == NULL; + } + bool isNone() const { - return p == Py_None; + return p == _None(); } 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); + return Py::_Unicode_Check( p ); + } + + bool isBoolean() const + { + return Py::_Boolean_Check( p ); } // Commands void setAttr (const std::string& s, const Object& value) { if(PyObject_SetAttrString (p, const_cast(s.c_str()), *value) == -1) - throw AttributeError ("getAttr failed."); + ifPyErrorThrowCxxException(); } void delAttr (const std::string& s) { if(PyObject_DelAttrString (p, const_cast(s.c_str())) == -1) - throw AttributeError ("delAttr failed."); + ifPyErrorThrowCxxException(); } // PyObject_SetItem is too weird to be using from C++ // so it is intentionally omitted. - void delItem (const Object& /*key*/) + void delItem (const Object& key) { - //if(PyObject_DelItem(p, *key) == -1) - // failed to link on Windows? - throw KeyError("delItem failed."); + if(PyObject_DelItem(p, *key) == -1) + ifPyErrorThrowCxxException(); } - // Equality and comparison use PyObject_Compare + + // Equality and comparison use PyObject_RichCompareBool bool operator==(const Object& o2) const { - int k = PyObject_Compare (p, *o2); - if (PyErr_Occurred()) throw Exception(); - return k == 0; + int k = PyObject_RichCompareBool (p, *o2, Py_EQ); + ifPyErrorThrowCxxException(); + return k != 0; } bool operator!=(const Object& o2) const { - int k = PyObject_Compare (p, *o2); - if (PyErr_Occurred()) throw Exception(); + int k = PyObject_RichCompareBool (p, *o2, Py_NE); + ifPyErrorThrowCxxException(); return k != 0; - } bool operator>=(const Object& o2) const { - int k = PyObject_Compare (p, *o2); - if (PyErr_Occurred()) throw Exception(); - return k >= 0; + int k = PyObject_RichCompareBool (p, *o2, Py_GE); + ifPyErrorThrowCxxException(); + return k != 0; } bool operator<=(const Object& o2) const { - int k = PyObject_Compare (p, *o2); - if (PyErr_Occurred()) throw Exception(); - return k <= 0; + int k = PyObject_RichCompareBool (p, *o2, Py_LE); + ifPyErrorThrowCxxException(); + return k != 0; } bool operator<(const Object& o2) const { - int k = PyObject_Compare (p, *o2); - if (PyErr_Occurred()) throw Exception(); - return k < 0; + int k = PyObject_RichCompareBool (p, *o2, Py_LT); + ifPyErrorThrowCxxException(); + return k != 0; } bool operator>(const Object& o2) const { - int k = PyObject_Compare (p, *o2); - if (PyErr_Occurred()) throw Exception(); - return k > 0; + int k = PyObject_RichCompareBool (p, *o2, Py_GT); + ifPyErrorThrowCxxException(); + 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()); } + // Python special Boolean values + inline Object False() + { + return Object(Py::_False()); + } + + inline Object True() + { + return Object(Py::_True()); + } + // 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 boolean + class Boolean: public Object + { + public: + // Constructor + Boolean (PyObject *pyob, bool owned = false) + : Object (pyob, owned) + { + validate(); + } + + Boolean (const Boolean& ob): Object(*ob) + { + validate(); + } + + // create from bool + Boolean (bool v=false) + { + set(PyBool_FromLong(v ? 1 : 0), true); + validate(); + } + + explicit Boolean (const Object& ob) + : Object( *ob ) + { + validate(); + } + + // Assignment increases reference count on pointer + + Boolean& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Boolean& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && PyObject_IsTrue(pyob) != -1; + } + // convert to long + operator bool() const + { + return PyObject_IsTrue (ptr()) != 0; + } + Boolean& operator= (bool v) + { + set (PyBool_FromLong (v ? 1 : 0), true); + return *this; + } + }; // =============================================== // class Int class Int: public Object { public: // Constructor - explicit Int (PyObject *pyob, bool owned = false): Object (pyob, owned) + Int (PyObject *pyob, bool owned = false): Object (pyob, owned) { validate(); } Int (const Int& ob): Object(*ob) { validate(); } // create from long Int (long v = 0L): Object(PyInt_FromLong(v), true) { validate(); } -#ifdef HAVE_LONG_LONG - // create from long long - Int (PY_LONG_LONG v): Object(PyLong_FromLongLong(v), true) - { - validate(); - } - // create from unsigned long long - Int (unsigned PY_LONG_LONG v): Object(PyLong_FromUnsignedLongLong(v), true) - { - validate(); - } -#endif - // create from int Int (int v) { long w = v; set(PyInt_FromLong(w), true); validate(); } // create from bool Int (bool v) { long w = v ? 1 : 0; set(PyInt_FromLong(w), true); validate(); } explicit 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()); } #ifdef HAVE_LONG_LONG // convert to long long PY_LONG_LONG asLongLong() const { return PyLong_AsLongLong (ptr()); } // convert to unsigned long long unsigned PY_LONG_LONG asUnsignedLongLong() const { return PyLong_AsUnsignedLongLong (ptr()); } #endif // 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; } #ifdef HAVE_LONG_LONG // assign from long long Int& operator= (PY_LONG_LONG v) { set (PyLong_FromLongLong (v), true); return *this; } // assign from unsigned long long Int& operator= (unsigned PY_LONG_LONG v) { set (PyLong_FromUnsignedLongLong (v), true); return *this; } #endif }; // =============================================== // class Long class Long: public Object { public: // Constructor - explicit Long (PyObject *pyob, bool owned = false): Object (pyob, owned) + explicit Long (PyObject *pyob, bool owned = false) + : Object (pyob, owned) { validate(); } - Long (const Long& ob): Object(ob.ptr()) + Long (const Long& ob) + : Object(ob.ptr()) + { + validate(); + } + + // try to create from any object + explicit Long (const Object& ob) + : Object(PyNumber_Long(*ob), true) { validate(); } // create from long explicit Long (long v = 0L) - : Object(PyLong_FromLong(v), true) + : Object(PyLong_FromLong(v), true) { validate(); } + // create from unsigned long explicit Long (unsigned long v) - : Object(PyLong_FromUnsignedLong(v), true) + : Object(PyLong_FromUnsignedLong(v), true) { validate(); } + // create from int explicit Long (int v) - : Object(PyLong_FromLong(static_cast(v)), true) + : Object(PyLong_FromLong(static_cast(v)), true) { validate(); } - // try to create from any object - Long (const Object& ob) - : Object(PyNumber_Long(*ob), true) +#ifdef HAVE_LONG_LONG + // create from long long + explicit Long( PY_LONG_LONG v ) + : Object( PyLong_FromLongLong( v ), true ) { validate(); } - // Assignment acquires new ownership of pointer - - Long& operator= (const Object& rhs) + // create from unsigned long long + explicit Long( unsigned PY_LONG_LONG v ) + : Object( PyLong_FromUnsignedLongLong( v ), true ) { - return (*this = *rhs); + validate(); } +#endif - 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()); - } - // convert to unsigned - operator unsigned long() const + + // Assignment acquires new ownership of pointer + Long& operator= (const Object& rhs) { - return PyLong_AsUnsignedLong (ptr()); + return *this = *rhs; } - operator double() const + + Long& operator= (PyObject* rhsp) { - return PyLong_AsDouble (ptr()); + if(ptr() != rhsp) + set (PyNumber_Long(rhsp), true); + return *this; } + // 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; } + +#ifdef HAVE_LONG_LONG + Long &operator=( PY_LONG_LONG v ) + { + set( PyLong_FromLongLong( v ), true ); + return *this; + } + + Long &operator=( unsigned PY_LONG_LONG v ) + { + set( PyLong_FromUnsignedLongLong( v ), true ); + return *this; + } +#endif + + // convert to long + long as_long() const + { + return PyLong_AsLong( ptr() ); + } + + operator long() const + { + return as_long(); + } + + operator int() const + { + return static_cast( as_long() ); + } + + // convert to unsigned + long as_unsigned_long() const + { + return PyLong_AsUnsignedLong( ptr() ); + } + + // convert to unsigned + operator unsigned long() const + { + return as_unsigned_long(); + } + + double as_double() const + { + return PyLong_AsDouble( ptr() ); + } + + operator double() const + { + return as_double(); + } + +#ifdef HAVE_LONG_LONG + PY_LONG_LONG as_long_long() const + { + return PyLong_AsLongLong( ptr() ); + } + + operator PY_LONG_LONG() const + { + return as_long_long(); + } + + unsigned PY_LONG_LONG as_unsigned_long_long() const + { + return PyLong_AsUnsignedLongLong( ptr() ); + } + + operator unsigned PY_LONG_LONG() const + { + return as_unsigned_long_long(); + } +#endif + + // prefix ++ + Long operator++() + { + set( PyNumber_Add( ptr(), *Long( 1 ) ) ); + return *this; + } + + // postfix ++ + Long operator++( int ) + { + Long a = *this; + set( PyNumber_Add( ptr(), *Long( 1 ) ) ); + return a; + } + + // prefix -- + Long operator--() + { + set( PyNumber_Subtract( ptr(), *Long( 1 ) ) ); + return *this; + } + + // postfix -- + Long operator--( int ) + { + Long a = *this; + set( PyNumber_Subtract( ptr(), *Long( 1 ) ) ); + return a; + } }; #ifdef HAVE_LONG_LONG // =============================================== // class LongLong class LongLong: public Object { public: // Constructor explicit LongLong (PyObject *pyob, bool owned = false): Object (pyob, owned) { validate(); } LongLong (const LongLong& ob): Object(ob.ptr()) { validate(); } // create from long long - explicit LongLong (long long v = 0L) + explicit LongLong (PY_LONG_LONG v = 0L) : Object(PyLong_FromLongLong(v), true) { validate(); } // create from unsigned long long - explicit LongLong (unsigned long long v) + explicit LongLong (unsigned PY_LONG_LONG v) : Object(PyLong_FromUnsignedLongLong(v), true) { validate(); } // create from long explicit LongLong (long v) : Object(PyLong_FromLongLong(v), true) { validate(); } // create from unsigned long explicit LongLong (unsigned long v) : Object(PyLong_FromUnsignedLongLong(v), true) { validate(); } // create from int explicit LongLong (int v) - : Object(PyLong_FromLongLong(static_cast(v)), true) + : Object(PyLong_FromLongLong(static_cast(v)), true) { validate(); } // try to create from any object LongLong (const Object& ob) : Object(PyNumber_Long(*ob), true) { validate(); } // Assignment acquires new ownership of pointer LongLong& operator= (const Object& rhs) { return (*this = *rhs); } LongLong& 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 long - operator long long() const + operator PY_LONG_LONG() const { return PyLong_AsLongLong (ptr()); } // convert to unsigned long - operator unsigned long long() const + operator unsigned PY_LONG_LONG() const { return PyLong_AsUnsignedLongLong (ptr()); } // convert to long operator long() const { return PyLong_AsLong (ptr()); } // convert to unsigned operator unsigned long() const { return PyLong_AsUnsignedLong (ptr()); } operator double() const { return PyLong_AsDouble (ptr()); } // assign from an int LongLong& operator= (int v) { set(PyLong_FromLongLong (long(v)), true); return *this; } // assign from long long - LongLong& operator= (long long v) + LongLong& operator= (PY_LONG_LONG v) { set(PyLong_FromLongLong (v), true); return *this; } // assign from unsigned long long - LongLong& operator= (unsigned long long v) + LongLong& operator= (unsigned PY_LONG_LONG v) { set(PyLong_FromUnsignedLongLong (v), true); return *this; } // assign from long LongLong& operator= (long v) { set(PyLong_FromLongLong (v), true); return *this; } // assign from unsigned long LongLong& operator= (unsigned long v) { set(PyLong_FromUnsignedLongLong (v), true); return *this; } }; #endif // =============================================== // 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 represents that. // In basic Python T is always "Object". // seqref is what you get if you get elements from a non-const SeqBase. // Note: seqref could probably be a nested class in SeqBase 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 class seqref { protected: SeqBase& s; // the sequence - int offset; // item number + sequence_index_type offset; // item number T the_item; // lvalue public: seqref (SeqBase& seq, sequence_index_type j) - : s(seq), offset(j), the_item (s.getItem(j)) + : s(seq), offset(j), the_item (s.getItem(j)) {} seqref (const seqref& range) - : s(range.s), offset(range.offset), the_item(range.the_item) + : 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&>(obj)) - , offset( 0 ) - , the_item(s.getItem(offset)) + : s(dynamic_cast< SeqBase&>(obj)) + , offset( 0 ) + , the_item(s.getItem(offset)) {} ~seqref() {} operator T() const { // rvalue return the_item; } seqref& operator=(const seqref& rhs) { //used as lvalue the_item = rhs.the_item; s.setItem(offset, the_item); return *this; } seqref& 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 // ...the base class for all sequence types template class SeqBase: public Object { public: // STL definitions - typedef size_t size_type; + typedef PyCxx_ssize_t size_type; typedef seqref reference; typedef T const_reference; typedef seqref* pointer; typedef int difference_type; typedef T value_type; // TMM: 26Jun'01 virtual size_type max_size() const { - return std::string::npos; // ? + return static_cast( std::string::npos ); // why this constant - its not from python? } virtual size_type capacity() const { return size(); } - virtual void swap(SeqBase& c) + virtual void swap( SeqBase &c ) { SeqBase temp = c; c = ptr(); set(temp.ptr()); } - virtual size_type size () const + virtual size_type size() const { return PySequence_Length (ptr()); } explicit SeqBase () - :Object(PyTuple_New(0), true) + : Object( PyTuple_New( 0 ), true ) { validate(); } explicit SeqBase (PyObject* pyob, bool owned=false) - : Object(pyob, owned) + : Object( pyob, owned ) { validate(); } SeqBase (const Object& ob): Object(ob) { validate(); } // Assignment acquires new ownership of pointer SeqBase& operator= (const Object& rhs) { return (*this = *rhs); } SeqBase& 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 + Py_ssize_t length () const { return PySequence_Length (ptr()); } // Element access const T operator[](sequence_index_type index) const { return getItem(index); } seqref operator[](sequence_index_type index) { return seqref(*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(); + ifPyErrorThrowCxxException(); } } SeqBase repeat (int count) const { return SeqBase (PySequence_Repeat (ptr(), count), true); } SeqBase concat (const SeqBase& other) const { return SeqBase (PySequence_Concat(ptr(), *other), true); } // more STL compatability const T front () const { return getItem(0); } seqref front() { - return seqref(this, 0); + return seqref(*this, 0); } - const T back () const + const T back() const { return getItem(size()-1); } seqref back() { - return seqref(this, size()-1); + return seqref(*this, size()-1); } - void verify_length(size_type required_size) const + void verify_length( size_type required_size ) const { if (size() != required_size) - throw IndexError ("Unexpected SeqBase length."); + throw IndexError ("Unexpected SeqBase length."); } - void verify_length(size_type min_size, size_type max_size) const + 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 length."); + throw IndexError ("Unexpected SeqBase length."); } - class iterator - : public random_access_iterator_parent(seqref) + class iterator: public random_access_iterator_parent(seqref) { protected: friend class SeqBase; SeqBase* seq; - int count; + sequence_index_type count; public: ~iterator () {} iterator () - : seq( 0 ) - , count( 0 ) + : seq( 0 ) + , count( 0 ) {} - iterator (SeqBase* s, int where) - : seq( s ) - , count( where ) + iterator (SeqBase* s, sequence_index_type where) + : seq( s ) + , count( where ) {} iterator (const iterator& other) - : seq( other.seq ) - , count( other.count ) + : seq( other.seq ) + , count( other.count ) {} bool eql (const iterator& other) const { - return (*seq == *other.seq) && (count == other.count); + return (seq->ptr() == other.seq->ptr()) && (count == other.count); } bool neq (const iterator& other) const { - return (*seq != *other.seq) || (count != other.count); + return (seq->ptr() != other.seq->ptr()) || (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 operator*() { return seqref(*seq, count); } seqref operator[] (sequence_index_type i) { return seqref(*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 + iterator operator+(sequence_index_type n) const { return iterator(seq, count + n); } - iterator operator-(int n) const + iterator operator-(sequence_index_type n) const { return iterator(seq, count - n); } - iterator& operator+=(int n) + iterator& operator+=(sequence_index_type n) { count = count + n; return *this; } - iterator& operator-=(int n) + iterator& operator-=(sequence_index_type n) { count = count - n; return *this; } int operator-(const iterator& other) const { if (*seq != *other.seq) - throw RuntimeError ("SeqBase::iterator comparison error"); + throw RuntimeError ("SeqBase::iterator comparison error"); return count - other.count; } // prefix ++ iterator& operator++ () - { count++; return *this;} + { + count++; + return *this; + } // postfix ++ iterator operator++ (int) - { return iterator(seq, count++);} + { + return iterator(seq, count++); + } // prefix -- iterator& operator-- () - { count--; return *this;} + { + count--; + return *this; + } // postfix -- iterator operator-- (int) - { return iterator(seq, count--);} + { + 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::iterator iterator begin () { return iterator(this, 0); } iterator end () { return iterator(this, length()); } class const_iterator - : public random_access_iterator_parent(const Object) + : public random_access_iterator_parent(const Object) { protected: friend class SeqBase; const SeqBase* seq; sequence_index_type count; + private: + const_iterator (const SeqBase* s, sequence_index_type where) + : seq( s ) + , count( where ) + {} + public: ~const_iterator () {} const_iterator () - : seq( 0 ) - , count( 0 ) - {} - - const_iterator (const SeqBase* s, int where) - : seq( s ) - , count( where ) + : seq( 0 ) + , count( 0 ) {} const_iterator(const const_iterator& other) - : seq( other.seq ) - , count( other.count ) + : 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 + const_iterator operator+(sequence_index_type n) const { return const_iterator(seq, count + n); } bool eql (const const_iterator& other) const { - return (*seq == *other.seq) && (count == other.count); + return (seq->ptr() == other.seq->ptr()) && (count == other.count); } bool neq (const const_iterator& other) const { - return (*seq != *other.seq) || (count != other.count); + return (seq->ptr() != other.seq->ptr()) || (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) + const_iterator operator-(sequence_index_type n) { return const_iterator(seq, count - n); } - const_iterator& operator+=(int n) + const_iterator& operator+=(sequence_index_type n) { count = count + n; return *this; } - const_iterator& operator-=(int n) + const_iterator& operator-=(sequence_index_type n) { count = count - n; return *this; } int operator-(const const_iterator& other) const { if (*seq != *other.seq) throw RuntimeError ("SeqBase::const_iterator::- error"); return count - other.count; } // prefix ++ const_iterator& operator++ () - { count++; return *this;} + { + count++; + return *this; + } // postfix ++ const_iterator operator++ (int) - { return const_iterator(seq, count++);} + { + return const_iterator(seq, count++); + } // prefix -- const_iterator& operator-- () - { count--; return *this;} + { + count--; + return *this; + } // postfix -- const_iterator operator-- (int) - { return const_iterator(seq, count--);} + { + return const_iterator(seq, count--); + } }; // end of class SeqBase::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 Sequence; template bool operator==(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator!=(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator< (const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator> (const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator<=(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator>=(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator==(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator!=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator< (const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator> (const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator<=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator>=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::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 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(v.c_str()),1), true) + :Object(PyString_FromStringAndSize( const_cast(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; + 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(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(v.data()),1), true); return *this; } Char& operator= (Py_UNICODE v) { set(PyUnicode_FromUnicode (&v, 1), true); return *this; } + long ord() + { + if( Py::_Unicode_Check( ptr() ) ) + { + Py_UNICODE *unicode = PyUnicode_AS_UNICODE( ptr() ); + return static_cast( unicode[0] ); + } + else + { + unsigned char *str = reinterpret_cast( PyString_AS_STRING( ptr() ) ); + return static_cast( str[0] ); + } + } + // Conversion operator String() const; operator std::string () const { return std::string(PyString_AsString (ptr())); } }; +#ifdef PYCXX_PYTHON_2TO3 + // String and Bytes compatible with Python3 version in 6.0.0 PyCXX + class Bytes; + class String: public SeqBase { public: virtual size_type capacity() const { return max_size(); } - explicit String (PyObject *pyob, bool owned = false): SeqBase(pyob, owned) + explicit String( PyObject *pyob, bool owned = false) + : SeqBase( pyob, owned ) { validate(); } - String (const Object& ob): SeqBase(ob) + String( const Object& ob): SeqBase(ob) { validate(); } String() - : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) + : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) { validate(); } String( const std::string& v ) - : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), - static_cast( v.length() ) ), true ) + : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), v.length() ), true ) { validate(); } - String( const char *s, const char *encoding, const char *error="strict" ) - : SeqBase( PyUnicode_Decode( s, strlen( s ), encoding, error ), true ) + String( const Py_UNICODE *s, int length ) + : SeqBase( PyUnicode_FromUnicode( s, length ), true ) + { + validate(); + } + + String( const char *s, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s, strlen( s ), encoding, error ), true ) { validate(); } String( const char *s, int len, const char *encoding, const char *error="strict" ) - : SeqBase( PyUnicode_Decode( s, len, encoding, error ), true ) + : SeqBase( PyUnicode_Decode( s, len, encoding, error ), true ) { validate(); } String( const std::string &s, const char *encoding, const char *error="strict" ) - : SeqBase( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true ) + : SeqBase( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true ) { validate(); } - String( const std::string& v, std::string::size_type vsize ) - : SeqBase(PyString_FromStringAndSize( const_cast(v.data()), - static_cast( vsize ) ), true) + String( const char *v, int vsize ) + : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) { validate(); } - String( const char *v, int vsize ) + String( const char *v ) + : SeqBase( 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( v.data() ), v.length() ), true ); + return *this; + } + String& operator=( const unicodestring &v ) + { + set( PyUnicode_FromUnicode( const_cast( v.data() ), v.length() ), true ); + return *this; + } + + // Encode + Bytes encode( const char *encoding, const char *error="strict" ) const; + + // Queries + virtual size_type size() const + { + if( isUnicode() ) + { + return PyUnicode_GET_SIZE (ptr()); + } + else + { + return PyString_Size (ptr()); + } + } + + operator std::string() const + { + return as_std_string( "utf-8" ); + } + + std::string as_std_string( const char *encoding, const char *error="strict" ) const; + + unicodestring as_unicodestring() const + { + if( isUnicode() ) + { + return unicodestring( PyUnicode_AS_UNICODE( ptr() ), + PyUnicode_GET_SIZE( ptr() ) ); + } + else + { + throw TypeError("can only return unicodestring from Unicode object"); + } + } + + const Py_UNICODE *unicode_data() const + { + if( isUnicode() ) + { + return PyUnicode_AS_UNICODE( ptr() ); + } + else + { + throw TypeError("can only return unicode_data from Unicode object"); + } + } + }; + class Bytes: public SeqBase + { + public: + virtual size_type capacity() const + { + return max_size(); + } + + explicit Bytes (PyObject *pyob, bool owned = false) + : SeqBase(pyob, owned) + { + validate(); + } + + Bytes (const Object& ob): SeqBase(ob) + { + validate(); + } + + Bytes() + : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) + { + validate(); + } + + Bytes( const std::string& v ) + : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), v.length()), true ) + { + validate(); + } + + Bytes( const char *v, size_type vsize ) + : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) + { + validate(); + } + + Bytes( const char *v ) + : SeqBase( PyString_FromString( v ), true ) + { + validate(); + } + + // Assignment acquires new ownership of pointer + Bytes &operator= ( const Object& rhs ) + { + return *this = *rhs; + } + + Bytes &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 + Bytes &operator= (const std::string& v) + { + set( PyString_FromStringAndSize( const_cast( v.data() ), v.length() ), true ); + return *this; + } + Bytes &operator= (const unicodestring& v) + { + set( PyUnicode_FromUnicode( const_cast( v.data() ), v.length() ), true ); + return *this; + } + + String decode( const char *encoding, const char *error="strict" ) + { + return Object( PyString_AsDecodedObject( ptr(), encoding, error ), true ); + } + + // Queries + virtual size_type size () const + { + if( isUnicode() ) + { + return PyUnicode_GET_SIZE (ptr()); + } + else + { + return 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( PyString_Size( ptr() ) ) ); + } + } + + unicodestring as_unicodestring() const + { + if( isUnicode() ) + { + return unicodestring( PyUnicode_AS_UNICODE( ptr() ), + static_cast( PyUnicode_GET_SIZE( ptr() ) ) ); + } + else + { + throw TypeError("can only return unicodestring from Unicode object"); + } + } + }; + +#else + // original PyCXX 5.4.x version of String + class String: public SeqBase + { + public: + virtual size_type capacity() const + { + return max_size(); + } + + explicit String (PyObject *pyob, bool owned = false): SeqBase(pyob, owned) + { + validate(); + } + + String (const Object& ob): SeqBase(ob) + { + validate(); + } + + String() + : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) + { + validate(); + } + + String( const std::string& v ) + : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), v.length() ), true ) + { + validate(); + } + + String( const char *s, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s, strlen( s ), encoding, error ), true ) + { + validate(); + } + + String( const char *s, size_type len, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s, len, encoding, error ), true ) + { + validate(); + } + + String( const std::string &s, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true ) + { + validate(); + } + + String( const char *v, size_type vsize ) : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) { validate(); } String( const char* v ) : SeqBase( 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( v.data() ), - static_cast( v.length() ) ), true ); + set( PyString_FromStringAndSize( const_cast( v.data() ), v.length() ), true ); return *this; } String& operator= (const unicodestring& v) { - set( PyUnicode_FromUnicode( const_cast( v.data() ), - static_cast( v.length() ) ), true ); + set( PyUnicode_FromUnicode( const_cast( v.data() ), v.length() ), true ); return *this; } // Encode - String encode( const char *encoding, const char *error="strict" ) + String encode( const char *encoding, const char *error="strict" ) const { if( isUnicode() ) - { - return String( PyUnicode_AsEncodedString( ptr(), encoding, error ) ); - } + { + return String( PyUnicode_AsEncodedString( ptr(), encoding, error ), true ); + } else - { - return String( PyString_AsEncodedObject( ptr(), encoding, error ) ); - } + { + return String( PyString_AsEncodedObject( ptr(), encoding, error ), true ); + } } String decode( const char *encoding, const char *error="strict" ) { - return Object( PyString_AsDecodedObject( ptr(), encoding, error ) ); + return Object( PyString_AsDecodedObject( ptr(), encoding, error ), true ); } // Queries virtual size_type size () const { if( isUnicode() ) - { - return static_cast( PyUnicode_GET_SIZE (ptr()) ); - } + { + return PyUnicode_GET_SIZE (ptr()); + } else - { - return static_cast( PyString_Size (ptr()) ); - } + { + return PyString_Size (ptr()); + } } operator std::string () const { return as_std_string(); } std::string as_std_string() const { if( isUnicode() ) - { -#ifdef Py_USING_UNICODE - Py::unicodestring u = Py::String(ptr()).as_unicodestring(); - std::string s; - std::copy(u.begin(), u.end(), std::back_inserter(s)); - return s; -#else + { throw TypeError("cannot return std::string from Unicode object"); -#endif - } + } else - { - return std::string( PyString_AsString( ptr() ), static_cast( PyString_Size( ptr() ) ) ); - } + { + return std::string( PyString_AsString( ptr() ), static_cast( PyString_Size( ptr() ) ) ); + } } + std::string as_std_string( const char *encoding, const char *error="strict" ) const; + unicodestring as_unicodestring() const { if( isUnicode() ) - { + { return unicodestring( PyUnicode_AS_UNICODE( ptr() ), - static_cast( PyUnicode_GET_SIZE( ptr() ) ) ); - } + static_cast( PyUnicode_GET_SIZE( ptr() ) ) ); + } else - { + { throw TypeError("can only return unicodestring from Unicode object"); - } + } } }; +#endif // ================================================== // 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(); + ifPyErrorThrowCxxException(); } } // 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(); + ifPyErrorThrowCxxException(); } } } // 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(); + ifPyErrorThrowCxxException(); } } } // 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 TupleN: public Tuple + { + public: + TupleN() + : Tuple( 0 ) + { + } + + TupleN( const Object &obj1 ) + : Tuple( 1 ) + { + setItem( 0, obj1 ); + } + + TupleN( const Object &obj1, const Object &obj2 ) + : Tuple( 2 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3 ) + : Tuple( 3 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4 ) + : Tuple( 4 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5 ) + : Tuple( 5 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6 ) + : Tuple( 6 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6, + const Object &obj7 ) + : Tuple( 7 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + setItem( 6, obj7 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6, + const Object &obj7, const Object &obj8 ) + : Tuple( 8 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + setItem( 6, obj7 ); + setItem( 7, obj8 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6, + const Object &obj7, const Object &obj8, const Object &obj9 ) + : Tuple( 9 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + setItem( 6, obj7 ); + setItem( 7, obj8 ); + setItem( 8, obj9 ); + } + + virtual ~TupleN() + { } + }; + + // ================================================== // 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) + List (size_type 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(); + ifPyErrorThrowCxxException(); } } } // List from a sequence List (const Sequence& s): Sequence() { - int n = (int)s.length(); + size_type 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(); + ifPyErrorThrowCxxException(); } } } 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(); + ifPyErrorThrowCxxException(); } } void append (const Object& ob) { if(PyList_Append (ptr(), *ob) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } } void insert (int i, const Object& ob) { if(PyList_Insert (ptr(), i, *ob) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } } void sort () { if(PyList_Sort(ptr()) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } } void reverse () { if(PyList_Reverse(ptr()) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } } }; // Mappings // ================================================== template class mapref { protected: MapBase& s; // the map Object key; // item key T the_item; public: mapref (MapBase& map, const std::string& k) : s(map), the_item() { key = String(k); if(map.hasKey(key)) the_item = map.getItem(key); } mapref (MapBase& map, const Object& k) : s(map), key(k), the_item() { if(map.hasKey(key)) the_item = map.getItem(key); } virtual ~mapref() {} // MapBase stuff // lvalue mapref& operator=(const mapref& other) { if(this == &other) return *this; the_item = other.the_item; s.setItem(key, other.the_item); return *this; } mapref& 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 isInstance () const { return the_item.isInstance(); } 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 template< class T > bool operator==(const mapref& left, const mapref& right) { return true; // NOT completed. } template< class T > bool operator!=(const mapref& left, const mapref& right) { return true; // not completed. } template class MapBase: public Object { protected: explicit MapBase() {} 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 PyCxx_ssize_t size_type; typedef Object key_type; typedef mapref data_type; typedef std::pair< const T, T > value_type; typedef std::pair< const T, mapref > reference; typedef const std::pair< const T, const T > const_reference; typedef std::pair< const T, mapref > pointer; // Constructor explicit MapBase (PyObject *pyob, bool owned = false): Object(pyob, owned) { validate(); } // TMM: 02Jul'01 - changed MapBase to Object in next line MapBase (const Object& ob): Object(ob) { validate(); } // Assignment acquires new ownership of pointer MapBase& operator= (const Object& rhs) { return (*this = *rhs); } MapBase& 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 + virtual Py_ssize_t 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 operator[](const std::string& key) { return mapref(*this, key); } mapref operator[](const Object& key) { return mapref(*this, key); } - int length () const + Py_ssize_t length () const { return PyMapping_Length (ptr()); } bool hasKey (const std::string& s) const { return PyMapping_HasKeyString (ptr(),const_cast(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(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(s), *ob) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } } virtual void setItem (const std::string& s, const Object& ob) { if (PyMapping_SetItemString (ptr(), const_cast(s.c_str()), *ob) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } } virtual void setItem (const Object& s, const Object& ob) { if (PyObject_SetItem (ptr(), s.ptr(), ob.ptr()) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } } void delItem (const std::string& s) { if (PyMapping_DelItemString (ptr(), const_cast(s.c_str())) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } } void delItem (const Object& s) { if (PyMapping_DelItem (ptr(), *s) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } } // Queries List keys () const { - //return List(PyMapping_Keys(ptr()), true); - return List(PyObject_CallMethod(ptr(),const_cast("keys"),NULL), true); + static char keys[] = {'k', 'e', 'y', 's', 0}; + return List(PyObject_CallMethod( ptr(), keys, NULL ), 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 - // 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* rather than a MapBase 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 ) { 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 > pointer; typedef std::pair< const T, mapref > reference; friend class MapBase; // - MapBase* map; - List keys; // for iterating over the map - List::iterator pos; // index into the keys + MapBase *map; + List keys; // for iterating over the map + sequence_index_type pos; // index into the keys + + private: + iterator( MapBase* m, List k, sequence_index_type p ) + : map( m ) + , keys( k ) + , pos( p ) + {} public: ~iterator () {} iterator () : map( 0 ) , keys() , pos() {} - explicit iterator (MapBase* m, bool end = false ) + iterator (MapBase* m, bool end = false ) : map( m ) , keys( m->keys() ) - , pos( end ? keys.end() : keys.begin() ) + , pos( end ? keys.length() : 0 ) {} iterator (const iterator& other) : map( other.map ) , keys( other.keys ) , pos( other.pos ) {} reference operator*() { - Object key = *pos; + Object key = keys[ pos ]; return std::make_pair(key, mapref(*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; + return map->ptr() == right.map->ptr() && pos == right.pos; } bool neq( const iterator& right ) const { - return *map != *right.map || pos != right.pos; + return map->ptr() != right.map->ptr() || 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::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; - const MapBase* map; - List keys; // for iterating over the map - List::iterator pos; // index into the keys + const MapBase *map; + List keys; // for iterating over the map + sequence_index_type pos; // index into the keys + + private: + const_iterator( const MapBase* m, List k, int p ) + : map( m ) + , keys( k ) + , pos( p ) + {} public: ~const_iterator () {} const_iterator () : map( 0 ) , keys() , pos() {} - const_iterator (const MapBase* m, List k, List::iterator p ) + const_iterator (const MapBase* m, bool end = false ) : map( m ) - , keys( k ) - , pos( p ) + , keys( m->keys() ) + , pos( end ? keys.length() : 0 ) {} 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; + return map->ptr() == right.map->ptr() && pos == right.pos; } + bool neq( const const_iterator& right ) const { - return *map != *right.map || pos != right.pos; + return map->ptr() != right.map->ptr() || 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_reference operator*() + { + Object key = keys[ pos ]; + return std::make_pair( key, mapref( *map, key ) ); + } 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::const_iterator const_iterator begin () const { - return const_iterator(this, 0); + return const_iterator(this); } const_iterator end () const { - return const_iterator(this, length()); + return const_iterator(this, true); } }; // end of MapBase typedef MapBase Mapping; template bool operator==(const EXPLICIT_TYPENAME MapBase::iterator& left, const EXPLICIT_TYPENAME MapBase::iterator& right); template bool operator!=(const EXPLICIT_TYPENAME MapBase::iterator& left, const EXPLICIT_TYPENAME MapBase::iterator& right); template bool operator==(const EXPLICIT_TYPENAME MapBase::const_iterator& left, const EXPLICIT_TYPENAME MapBase::const_iterator& right); template bool operator!=(const EXPLICIT_TYPENAME MapBase::const_iterator& left, const EXPLICIT_TYPENAME MapBase::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) + Dict (const Object& 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 { public: // Constructor explicit Callable (): Object() {} 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())); + PyObject *result = PyObject_CallObject( ptr(), args.ptr() ); + if( result == NULL ) + { + ifPyErrorThrowCxxException(); + } + return asObject( result ); } // Call with keywords Object apply(const Tuple& args, const Dict& kw) const { - return asObject( PyEval_CallObjectWithKeywords( ptr(), args.ptr(), kw.ptr() ) ); + PyObject *result = PyEval_CallObjectWithKeywords( ptr(), args.ptr(), kw.ptr() ); + if( result == NULL ) + { + ifPyErrorThrowCxxException(); + } + return asObject( result ); } Object apply(PyObject* pargs = 0) const { - return apply(pargs ? Tuple(pargs) : Tuple()); + if( pargs == 0 ) + { + return apply( Tuple() ); + } + else + { + 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(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! } }; + // Call function helper + inline Object Object::callMemberFunction( const std::string &function_name ) const + { + Callable target( getAttr( function_name ) ); + Tuple args( 0 ); + return target.apply( args ); + } + + inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args ) const + { + Callable target( getAttr( function_name ) ); + return target.apply( args ); + } + + inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args, const Dict &kw ) const + { + Callable target( getAttr( function_name ) ); + return target.apply( args, kw ); + } + // 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 coerce(const Object& a, const Object& b) { PyObject *p1, *p2; p1 = *a; p2 = *b; if(PyNumber_Coerce(&p1,&p2) == -1) { - throw Exception(); + ifPyErrorThrowCxxException(); } return std::pair(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 + inline Object type(const BaseException&) // return the type of the error { PyObject *ptype, *pvalue, *ptrace; PyErr_Fetch(&ptype, &pvalue, &ptrace); Object result; if(ptype) result = ptype; PyErr_Restore(ptype, pvalue, ptrace); return result; } - inline Object value(const Exception&) // return the value of the error + inline Object value(const BaseException&) // 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 + inline Object trace(const BaseException&) // 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 String seqref::str () const { return the_item.str(); } template String seqref::repr () const { return the_item.repr(); } } // namespace Py #endif // __CXX_Objects__h diff --git a/python/cxx/CXX/Python2/PythonType.hxx b/python/cxx/CXX/Python2/PythonType.hxx new file mode 100644 index 0000000..7f26d87 --- /dev/null +++ b/python/cxx/CXX/Python2/PythonType.hxx @@ -0,0 +1,204 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) 1998 - 2007, The Regents of the University of California +// Produced at the Lawrence Livermore National Laboratory +// All rights reserved. +// +// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The +// full copyright notice is contained in the file COPYRIGHT located at the root +// of the PyCXX distribution. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or materials provided with the distribution. +// - Neither the name of the UC/LLNL nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF +// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +//----------------------------------------------------------------------------- + +#ifndef __CXX_PythonType__h +#define __CXX_PythonType__h + +namespace Py +{ + class PythonType + { + public: +#define B(n) (1<<(n)) + // if you define one sequence method you must define + // all of them except the assigns + + PythonType( size_t base_size, int itemsize, const char *default_name ); + virtual ~PythonType(); + + const char *getName() const; + const char *getDoc() const; + + PyTypeObject *type_object() const; + PythonType &name( const char *nam ); + PythonType &doc( const char *d ); + + PythonType &supportClass( void ); + PythonType &dealloc( void (*f)( PyObject* ) ); +#if defined( PYCXX_PYTHON_2TO3 ) + PythonType &supportPrint( void ); +#endif + PythonType &supportGetattr( void ); + PythonType &supportSetattr( void ); + PythonType &supportGetattro( void ); + PythonType &supportSetattro( void ); +#if defined( PYCXX_PYTHON_2TO3 ) + PythonType &supportCompare( void ); +#endif + PythonType &supportRichCompare( void ); + PythonType &supportRepr( void ); + PythonType &supportStr( void ); + PythonType &supportHash( void ); + PythonType &supportCall( void ); + + enum { + support_iter_iter = B(0), + support_iter_iternext = B(1) + }; + PythonType &supportIter( int methods_to_support= + support_iter_iter | + support_iter_iternext ); + + enum { + support_sequence_length = B(0), + support_sequence_repeat = B(1), + support_sequence_item = B(2), + support_sequence_slice = B(3), + support_sequence_concat = B(4), + support_sequence_ass_item = B(5), + support_sequence_ass_slice = B(6), + support_sequence_inplace_concat = B(7), + support_sequence_inplace_repeat = B(8), + support_sequence_contains = B(9) + }; + PythonType &supportSequenceType( int methods_to_support= + support_sequence_length | + support_sequence_repeat | + support_sequence_item | + support_sequence_slice | + support_sequence_concat + ); + + enum { + support_mapping_length = B(0), + support_mapping_subscript = B(1), + support_mapping_ass_subscript = B(2) + }; + PythonType &supportMappingType( int methods_to_support= + support_mapping_length | + support_mapping_subscript + ); + + enum { + support_number_add = B(0), + support_number_subtract = B(1), + support_number_multiply = B(2), + support_number_divide = B(3), + support_number_remainder = B(4), + support_number_divmod = B(5), + support_number_power = B(6), + support_number_negative = B(7), + support_number_positive = B(8), + support_number_absolute = B(9), + support_number_nonzero = B(10), + support_number_invert = B(11), + support_number_lshift = B(12), + support_number_rshift = B(13), + support_number_and = B(14), + support_number_xor = B(15), + support_number_or = B(16), + support_number_int = B(17), + support_number_long = B(18), + support_number_float = B(19), + support_number_oct = B(20), + support_number_hex = B(21) + }; + PythonType &supportNumberType( int methods_to_support= + support_number_add | + support_number_subtract | + support_number_multiply | + support_number_divide | + support_number_remainder | + support_number_divmod | + support_number_power | + support_number_negative | + support_number_positive | + support_number_absolute | + support_number_nonzero | + support_number_invert | + support_number_lshift | + support_number_rshift | + support_number_and | + support_number_xor | + support_number_or | + support_number_int | + support_number_long | + support_number_float | + support_number_oct | + support_number_hex + ); + + enum { + support_buffer_getreadbuffer = B(0), + support_buffer_getwritebuffer = B(1), + support_buffer_getsegcount = B(2) + }; + PythonType &supportBufferType( int methods_to_support= + support_buffer_getreadbuffer | + support_buffer_getwritebuffer | + support_buffer_getsegcount + ); +#undef B + + PythonType &set_tp_dealloc( void (*tp_dealloc)( PyObject * ) ); + PythonType &set_tp_init( int (*tp_init)( PyObject *self, PyObject *args, PyObject *kwds ) ); + PythonType &set_tp_new( PyObject *(*tp_new)( PyTypeObject *subtype, PyObject *args, PyObject *kwds ) ); + PythonType &set_methods( PyMethodDef *methods ); + + // call once all support functions have been called to ready the type + bool readyType(); + + protected: + PyTypeObject *table; + PySequenceMethods *sequence_table; + PyMappingMethods *mapping_table; + PyNumberMethods *number_table; + PyBufferProcs *buffer_table; + + private: + // + // prevent the compiler generating these unwanted functions + // + PythonType( const PythonType &tb ); // unimplemented + void operator=( const PythonType &t ); // unimplemented + + }; + +} // Namespace Py + +// End of __CXX_PythonType__h +#endif diff --git a/python/cxx/CXX/Python2/cxx_standard_exceptions.hxx b/python/cxx/CXX/Python2/cxx_standard_exceptions.hxx new file mode 100644 index 0000000..9065b33 --- /dev/null +++ b/python/cxx/CXX/Python2/cxx_standard_exceptions.hxx @@ -0,0 +1,46 @@ +#if !defined( PYCXX_STANDARD_EXCEPTION ) +#pragma error( "define PYCXX_STANDARD_EXCEPTION before including" ) +#endif + +PYCXX_STANDARD_EXCEPTION( SystemExit, BaseException ) +PYCXX_STANDARD_EXCEPTION( KeyboardInterrupt,BaseException ) +PYCXX_STANDARD_EXCEPTION( GeneratorExit, BaseException ) +#if !defined( PYCXX_6_2_COMPATIBILITY ) +PYCXX_STANDARD_EXCEPTION( Exception, BaseException ) +#endif +PYCXX_STANDARD_EXCEPTION( StopIteration, Exception ) +PYCXX_STANDARD_EXCEPTION( StandardError, Exception ) +PYCXX_STANDARD_EXCEPTION( BufferError, StandardError ) +PYCXX_STANDARD_EXCEPTION( ArithmeticError, StandardError ) +PYCXX_STANDARD_EXCEPTION( FloatingPointError, ArithmeticError ) +PYCXX_STANDARD_EXCEPTION( OverflowError, ArithmeticError ) +PYCXX_STANDARD_EXCEPTION( ZeroDivisionError, ArithmeticError ) +PYCXX_STANDARD_EXCEPTION( AssertionError, StandardError ) +PYCXX_STANDARD_EXCEPTION( AttributeError, StandardError ) +PYCXX_STANDARD_EXCEPTION( EnvironmentError, StandardError ) +PYCXX_STANDARD_EXCEPTION( IOError, EnvironmentError ) +PYCXX_STANDARD_EXCEPTION( OSError, EnvironmentError ) +#ifdef MS_WINDOWS +PYCXX_STANDARD_EXCEPTION( WindowsError, OSError ) +#endif +PYCXX_STANDARD_EXCEPTION( EOFError, StandardError ) +PYCXX_STANDARD_EXCEPTION( ImportError, StandardError ) +PYCXX_STANDARD_EXCEPTION( LookupError, StandardError ) +PYCXX_STANDARD_EXCEPTION( IndexError, LookupError ) +PYCXX_STANDARD_EXCEPTION( KeyError, LookupError ) +PYCXX_STANDARD_EXCEPTION( MemoryError, StandardError ) +PYCXX_STANDARD_EXCEPTION( NameError, StandardError ) +PYCXX_STANDARD_EXCEPTION( UnboundLocalError,NameError ) +PYCXX_STANDARD_EXCEPTION( ReferenceError, StandardError ) +PYCXX_STANDARD_EXCEPTION( RuntimeError, StandardError ) +PYCXX_STANDARD_EXCEPTION( NotImplementedError, RuntimeError ) +PYCXX_STANDARD_EXCEPTION( SyntaxError, StandardError ) +PYCXX_STANDARD_EXCEPTION( IndentationError, SyntaxError ) +PYCXX_STANDARD_EXCEPTION( TabError, IndentationError ) +PYCXX_STANDARD_EXCEPTION( SystemError, StandardError ) +PYCXX_STANDARD_EXCEPTION( TypeError, StandardError ) +PYCXX_STANDARD_EXCEPTION( ValueError, StandardError ) +PYCXX_STANDARD_EXCEPTION( UnicodeError, ValueError ) +PYCXX_STANDARD_EXCEPTION( UnicodeDecodeError, UnicodeError ) +PYCXX_STANDARD_EXCEPTION( UnicodeEncodeError, UnicodeError ) +PYCXX_STANDARD_EXCEPTION( UnicodeTranslateError,UnicodeError ) diff --git a/python/cxx/Version.hxx b/python/cxx/CXX/Version.hxx similarity index 97% copy from python/cxx/Version.hxx copy to python/cxx/CXX/Version.hxx index 8286e2f..fabce5f 100644 --- a/python/cxx/Version.hxx +++ b/python/cxx/CXX/Version.hxx @@ -1,46 +1,46 @@ //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __PyCXX_version_hxx__ #define __PyCXX_version_hxx__ -#define PYCXX_VERSION_MAJOR 5 -#define PYCXX_VERSION_MINOR 4 +#define PYCXX_VERSION_MAJOR 7 +#define PYCXX_VERSION_MINOR 1 #define PYCXX_VERSION_PATCH 0 #define PYCXX_MAKEVERSION( major, minor, patch ) ((major<<16)|(minor<<8)|(patch)) #define PYCXX_VERSION PYCXX_MAKEVERSION( PYCXX_VERSION_MAJOR, PYCXX_VERSION_MINOR, PYCXX_VERSION_PATCH ) #endif diff --git a/python/cxx/Version.hxx b/python/cxx/CXX/WrapPython.h similarity index 73% rename from python/cxx/Version.hxx rename to python/cxx/CXX/WrapPython.h index 8286e2f..6a73545 100644 --- a/python/cxx/Version.hxx +++ b/python/cxx/CXX/WrapPython.h @@ -1,46 +1,71 @@ //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- -#ifndef __PyCXX_version_hxx__ -#define __PyCXX_version_hxx__ +#ifndef __PyCXX_wrap_python_hxx__ +#define __PyCXX_wrap_python_hxx__ + +// On some platforms we have to include time.h to get select defined +#if !defined(__WIN32__) && !defined(WIN32) && !defined(_WIN32) && !defined(_WIN64) +#include +#endif + +// Prevent multiple conflicting definitions of swab from stdlib.h and unistd.h +#if defined(__sun) || defined(sun) +#if defined(_XPG4) +#undef _XPG4 +#endif +#endif + +// Python.h will redefine these and generate warning in the process +#undef _XOPEN_SOURCE +#undef _POSIX_C_SOURCE + +// pull in python definitions +#include + +// fix issue with Python assuming that isspace, toupper etc are macros +#if defined(isspace) +#undef isspace +#undef isupper +#undef islower +#undef isalnum +#undef isalpha +#undef toupper +#undef tolower +#endif -#define PYCXX_VERSION_MAJOR 5 -#define PYCXX_VERSION_MINOR 4 -#define PYCXX_VERSION_PATCH 0 -#define PYCXX_MAKEVERSION( major, minor, patch ) ((major<<16)|(minor<<8)|(patch)) -#define PYCXX_VERSION PYCXX_MAKEVERSION( PYCXX_VERSION_MAJOR, PYCXX_VERSION_MINOR, PYCXX_VERSION_PATCH ) #endif diff --git a/python/cxx/Exception.hxx b/python/cxx/Exception.hxx deleted file mode 100644 index 0f63440..0000000 --- a/python/cxx/Exception.hxx +++ /dev/null @@ -1,249 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (c) 1998 - 2007, The Regents of the University of California -// Produced at the Lawrence Livermore National Laboratory -// All rights reserved. -// -// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The -// full copyright notice is contained in the file COPYRIGHT located at the root -// of the PyCXX distribution. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the disclaimer below. -// - Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the -// documentation and/or materials provided with the distribution. -// - Neither the name of the UC/LLNL nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF -// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -//----------------------------------------------------------------------------- - -#ifndef __CXX_Exception_h -#define __CXX_Exception_h - -#include "WrapPython.h" -#include "Version.hxx" -#include "Config.hxx" -#include "IndirectPythonInterface.hxx" - -#include -#include - -// This mimics the Python structure, in order to minimize confusion -namespace Py -{ - class ExtensionExceptionType; - - class Object; - - class Exception - { - public: - Exception( ExtensionExceptionType &exception, const std::string& reason ); - Exception( ExtensionExceptionType &exception, Object &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()); - } - - Exception (PyObject* exception, Object &reason); - - 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/python/cxx/Extensions.hxx b/python/cxx/Extensions.hxx deleted file mode 100644 index e56819a..0000000 --- a/python/cxx/Extensions.hxx +++ /dev/null @@ -1,799 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (c) 1998 - 2007, The Regents of the University of California -// Produced at the Lawrence Livermore National Laboratory -// All rights reserved. -// -// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The -// full copyright notice is contained in the file COPYRIGHT located at the root -// of the PyCXX distribution. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the disclaimer below. -// - Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the -// documentation and/or materials provided with the distribution. -// - Neither the name of the UC/LLNL nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF -// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -//----------------------------------------------------------------------------- - -#ifndef __CXX_Extensions__h -#define __CXX_Extensions__h - - -#ifdef _MSC_VER -// disable warning C4786: symbol greater than 255 character, -// okay to ignore -#pragma warning(disable: 4786) -#endif - -#include "WrapPython.h" -#include "Version.hxx" -#include "Config.hxx" -#include "Objects.hxx" - -extern "C" -{ - extern PyObject py_object_initializer; -} - -#include -#include - -namespace Py -{ - class ExtensionModuleBase; - - // Make an Exception Type for use in raising custom exceptions - class ExtensionExceptionType : public Object - { - public: - ExtensionExceptionType(); - virtual ~ExtensionExceptionType(); - - // call init to create the type - void init( ExtensionModuleBase &module, const std::string& name, ExtensionExceptionType &parent ); - void init( ExtensionModuleBase &module, const std::string& name ); - }; - - - class MethodTable - { - public: - MethodTable(); - virtual ~MethodTable(); - - void add(const char* method_name, PyCFunction f, const char* doc="", int flag=1); - PyMethodDef* table(); - - protected: - std::vector 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 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(_name); - ext_meth_def.ml_meth = _handler; - ext_meth_def.ml_flags = METH_VARARGS; - ext_meth_def.ml_doc = const_cast(_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(_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(_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 - 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 *> method_map_t; - - static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) - { - std::string n( name ); - - method_map_t &mm = methods(); -if( mm.find(n) != mm.end() ) return; - - MethodDefExt *method_definition = new MethodDefExt - ( - name, - function, - method_varargs_call_handler, - doc - ); - - mm[n] = method_definition; - } - - static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) - { - std::string n( name ); - - method_map_t &mm = methods(); -if( mm.find(n) != mm.end() ) return; - - MethodDefExt *method_definition = new MethodDefExt - ( - name, - function, - method_keyword_call_handler, - doc - ); - - mm[n] = 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 *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 *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(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 *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(this); - - return (self->*meth_def->ext_varargs_function)( args ); - } - - private: - // - // prevent the compiler generating these unwanted functions - // - ExtensionModule( const ExtensionModule & ); //unimplemented - void operator=( const ExtensionModule & ); //unimplemented - }; - - - class PythonType - { - public: - // if you define one sequence method you must define - // all of them except the assigns - - PythonType (size_t base_size, int itemsize, const char *default_name ); - virtual ~PythonType (); - - const char *getName () const; - const char *getDoc () const; - - PyTypeObject* type_object () const; - PythonType & name (const char* nam); - PythonType & doc (const char* d); - PythonType & dealloc(void (*f)(PyObject*)); - - PythonType & supportPrint(void); - PythonType & supportGetattr(void); - PythonType & supportSetattr(void); - PythonType & supportGetattro(void); - PythonType & supportSetattro(void); - PythonType & supportCompare(void); - PythonType & supportRepr(void); - PythonType & supportStr(void); - PythonType & supportHash(void); - PythonType & supportCall(void); - PythonType & supportIter(void); - - PythonType & supportSequenceType(void); - PythonType & supportMappingType(void); - PythonType & supportNumberType(void); - PythonType & supportBufferType(void); - - protected: - PyTypeObject *table; - PySequenceMethods *sequence_table; - PyMappingMethods *mapping_table; - PyNumberMethods *number_table; - PyBufferProcs *buffer_table; - - void init_sequence(); - void init_mapping(); - void init_number(); - void init_buffer(); - - private: - // - // prevent the compiler generating these unwanted functions - // - PythonType (const PythonType& tb); // unimplemented - void operator=(const PythonType& t); // unimplemented - - }; // end of PythonType - - - - // Class PythonExtension is what you inherit from to create - // a new Python extension type. You give your class itself - // as the template parameter. - - // 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 & ); - virtual Object iter(); - virtual PyObject* iternext(); - - // Sequence methods - virtual int sequence_length(); - virtual Object sequence_concat( const Object & ); - virtual Object sequence_repeat( Py_ssize_t ); - virtual Object sequence_item( Py_ssize_t ); - virtual Object sequence_slice( Py_ssize_t, Py_ssize_t ); - virtual int sequence_ass_item( Py_ssize_t, const Object & ); - virtual int sequence_ass_slice( Py_ssize_t, Py_ssize_t, const Object & ); - - // Mapping - virtual int mapping_length(); - virtual Object mapping_subscript( const Object & ); - virtual int mapping_ass_subscript( const Object &, const Object & ); - - // Number - virtual int number_nonzero(); - virtual Object number_negative(); - virtual Object number_positive(); - virtual Object number_absolute(); - virtual Object number_invert(); - virtual Object number_int(); - virtual Object number_float(); - virtual Object number_long(); - virtual Object number_oct(); - virtual Object number_hex(); - virtual Object number_add( const Object & ); - virtual Object number_subtract( const Object & ); - virtual Object number_multiply( const Object & ); - virtual Object number_divide( const Object & ); - virtual Object number_remainder( const Object & ); - virtual Object number_divmod( const Object & ); - virtual Object number_lshift( const Object & ); - virtual Object number_rshift( const Object & ); - virtual Object number_and( const Object & ); - virtual Object number_xor( const Object & ); - virtual Object number_or( const Object & ); - virtual Object number_power( const Object &, const Object & ); - - // Buffer - virtual Py_ssize_t buffer_getreadbuffer( Py_ssize_t, void** ); - virtual Py_ssize_t buffer_getwritebuffer( Py_ssize_t, void** ); - virtual Py_ssize_t buffer_getsegcount( Py_ssize_t* ); - - private: - void missing_method( void ); - static PyObject *method_call_handler( PyObject *self, PyObject *args ); - }; - - template - class PythonExtension: public PythonExtensionBase - { - public: - static PyTypeObject* type_object() - { - return behaviors().type_object(); - } - - static int check( PyObject *p ) - { - // is p like me? - return p->ob_type == type_object(); - } - - static int check( const Object& ob ) - { - return check( ob.ptr()); - } - - - // - // every object needs getattr implemented - // to support methods - // - virtual Object getattr( const char *name ) - { - return getattr_methods( name ); - } - - protected: - explicit PythonExtension() - : PythonExtensionBase() - { - #ifdef PyObject_INIT - (void)PyObject_INIT( this, type_object() ); - #else - ob_refcnt = 1; - ob_type = type_object(); - #endif - - // every object must support getattr - behaviors().supportGetattr(); - } - - virtual ~PythonExtension() - {} - - static PythonType &behaviors() - { - static PythonType* p; - if( p == NULL ) - { -#if defined( _CPPRTTI ) || defined(__GNUG__) - const char *default_name = (typeid ( T )).name(); -#else - const char *default_name = "unknown"; -#endif - p = new PythonType( sizeof( T ), 0, default_name ); - p->dealloc( extension_object_deallocator ); - } - - return *p; - } - - - typedef Object (T::*method_varargs_function_t)( const Tuple &args ); - typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); - typedef std::map *> 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 ); - } - if( name == "__doc__" && type_object()->tp_doc != NULL ) - { - return Py::String( type_object()->tp_doc ); - } - -// trying to fake out being a class for help() -// else if( name == "__bases__" ) -// { -// return Py::Tuple(0); -// } -// else if( name == "__module__" ) -// { -// return Py::Nothing(); -// } -// else if( name == "__dict__" ) -// { -// return Py::Dict(); -// } - - return getattr_methods( _name ); - } - - // turn a name into function object - virtual Object getattr_methods( const char *_name ) - { - std::string name( _name ); - - method_map_t &mm = methods(); - - 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( name ); - - Tuple self( 2 ); - - self[0] = Object( this ); - self[1] = String( name ); - - MethodDefExt *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="" ) - { - std::string n( name ); - method_map_t &mm = methods(); -if( mm.find(n) != mm.end() ) return; - - MethodDefExt *method_definition = new MethodDefExt - ( - name, - function, - method_varargs_call_handler, - doc - ); - - mm[n] = method_definition; - } - - static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) - { - method_map_t &mm = methods(); - - MethodDefExt *method_definition = new MethodDefExt - ( - 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( self_in_cobject ); - - String name( self_and_name_tuple[1] ); - - method_map_t &mm = methods(); - MethodDefExt *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( self_in_cobject ); - - String name( self_and_name_tuple[1] ); - - method_map_t &mm = methods(); - MethodDefExt *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& other ); - void operator=( const PythonExtension& rhs ); - }; - - // - // ExtensionObject is an Object that will accept only T's. - // - template - class ExtensionObject: public Object - { - public: - - explicit ExtensionObject ( PyObject *pyob ) - : Object( pyob ) - { - validate(); - } - - ExtensionObject( const ExtensionObject& 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( ptr() ); - } - }; - -} // Namespace Py -// End of CXX_Extensions.h -#endif diff --git a/python/cxx/IndirectPythonInterface.cxx b/python/cxx/IndirectPythonInterface.cxx deleted file mode 100644 index 9efcc25..0000000 --- a/python/cxx/IndirectPythonInterface.cxx +++ /dev/null @@ -1,583 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (c) 1998 - 2007, The Regents of the University of California -// Produced at the Lawrence Livermore National Laboratory -// All rights reserved. -// -// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The -// full copyright notice is contained in the file COPYRIGHT located at the root -// of the PyCXX distribution. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the disclaimer below. -// - Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the -// documentation and/or materials provided with the distribution. -// - Neither the name of the UC/LLNL nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF -// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -//----------------------------------------------------------------------------- - -#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 - - -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/python/cxx/Readme.Kross.txt b/python/cxx/Readme.Kross.txt index 54697bf..b357587 100644 --- a/python/cxx/Readme.Kross.txt +++ b/python/cxx/Readme.Kross.txt @@ -1,5 +1,5 @@ -Kross uses PyCXX 5.4.0 (http://cxx.sourceforge.net/) +Kross uses PyCXX 7.1.0 (http://cxx.sourceforge.net/) to access the Python C API. See the patch-list for panding patches; http://sourceforge.net/tracker/?group_id=3180&atid=303180 diff --git a/python/cxx/Src/IndirectPythonInterface.cxx b/python/cxx/Src/IndirectPythonInterface.cxx new file mode 100644 index 0000000..ca62385 --- /dev/null +++ b/python/cxx/Src/IndirectPythonInterface.cxx @@ -0,0 +1,518 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) 1998 - 2007, The Regents of the University of California +// Produced at the Lawrence Livermore National Laboratory +// All rights reserved. +// +// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The +// full copyright notice is contained in the file COPYRIGHT located at the root +// of the PyCXX distribution. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or materials provided with the distribution. +// - Neither the name of the UC/LLNL nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF +// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +//----------------------------------------------------------------------------- + +#include "CXX/IndirectPythonInterface.hxx" + +namespace Py +{ +bool _CFunction_Check( PyObject *op ) { return op->ob_type == _CFunction_Type(); } +bool _Complex_Check( PyObject *op ) { return op->ob_type == _Complex_Type(); } +bool _Dict_Check( PyObject *op ) { return op->ob_type == _Dict_Type(); } +bool _Float_Check( PyObject *op ) { return op->ob_type == _Float_Type(); } +#if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +bool _Function_Check( PyObject *op ) { return op->ob_type == _Function_Type(); } +#endif +bool _Boolean_Check( PyObject *op ) { return op->ob_type == _Bool_Type(); } +bool _List_Check( PyObject *op ) { return op->ob_type == _List_Type(); } +bool _Long_Check( PyObject *op ) { return op->ob_type == _Long_Type(); } +#if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +bool _Method_Check( PyObject *op ) { return op->ob_type == _Method_Type(); } +#endif +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 _TraceBack_Check( PyObject *op ) { return op->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(); } +bool _Unicode_Check( PyObject *op ) { return op->ob_type == _Unicode_Type(); } +#if PY_MAJOR_VERSION == 2 +bool _String_Check( PyObject *op ) { return op->ob_type == _String_Type(); } +bool _Int_Check( PyObject *op ) { return op->ob_type == _Int_Type(); } +bool _CObject_Check( PyObject *op ) { return op->ob_type == _CObject_Type(); } +#endif +#if PY_MAJOR_VERSION >= 3 +bool _Bytes_Check( PyObject *op ) { return op->ob_type == _Bytes_Type(); } +#endif + +#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) + +# if defined(MS_WINDOWS) +# include + + +static HMODULE python_dll; + +# define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ + static PyObject *ptr_Exc_##eclass = NULL; + +# if PY_MAJOR_VERSION == 2 +# include "CXX/Python2/cxx_standard_exceptions.hxx" +# else +# include "CXX/Python3/cxx_standard_exceptions.hxx" +# endif + +# undef PYCXX_STANDARD_EXCEPTION + +static PyTypeObject *ptr__CFunction_Type = NULL; +static PyTypeObject *ptr__Complex_Type = NULL; +static PyTypeObject *ptr__Dict_Type = NULL; +static PyTypeObject *ptr__Float_Type = NULL; +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +static PyTypeObject *ptr__Function_Type = NULL; +# endif +static PyTypeObject *ptr__Bool_Type = NULL; +static PyTypeObject *ptr__List_Type = NULL; +static PyTypeObject *ptr__Long_Type = NULL; +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +static PyTypeObject *ptr__Method_Type = NULL; +# endif +static PyTypeObject *ptr__Module_Type = NULL; +static PyTypeObject *ptr__Range_Type = NULL; +static PyTypeObject *ptr__Slice_Type = NULL; +static PyTypeObject *ptr__TraceBack_Type = NULL; +static PyTypeObject *ptr__Tuple_Type = NULL; +static PyTypeObject *ptr__Type_Type = NULL; +static PyTypeObject *ptr__Unicode_Type = NULL; +# if PY_MAJOR_VERSION == 2 +static PyTypeObject *ptr__Int_Type = NULL; +static PyTypeObject *ptr__String_Type = NULL; +static PyTypeObject *ptr__CObject_Type = NULL; +# endif +# if PY_MAJOR_VERSION >= 3 +static PyTypeObject *ptr__Bytes_Type = NULL; +# endif + +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +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_VerboseFlag = NULL; + +static char **ptr__Py_PackageContext = NULL; +# endif + +# 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)]; + + _snprintf( python_dll_name, sizeof(python_dll_name_format) / sizeof(char) - 1, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); + + python_dll = LoadLibraryA( python_dll_name ); + if( python_dll == NULL ) + return false; + + try + { +# ifdef Py_REF_DEBUG + ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); +# endif +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) + 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_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); + ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); +# endif + +# define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) + ptr_Exc_#eclass = GetPyTypeObject_As_PyTypeObjectPointer( "PyExc_" #eclass ); + +# if PY_MAJOR_VERSION == 2 +# include "CXX/Python2/cxx_standard_exceptions.hxx" +# else +# include "CXX/Python3/cxx_standard_exceptions.hxx" +# endif + +# undef PYCXX_STANDARD_EXCEPTION + + ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); + +# if PY_MAJOR_VERSION == 2 + ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_ZeroStruct" ); +# else + ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_FalseStruct" ); +# endif + ptr__PyTrue = GetPyObject_As_PyObjectPointer( "_Py_TrueStruct" ); + + ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); + ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); + ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); + ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) + ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); +# endif + ptr__Bool_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBool_Type" ); + ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); + ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) + ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); +# endif + 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__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); + ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); + ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); + ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); +# if PY_MAJOR_VERSION == 2 + ptr__String_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyString_Type" ); + ptr__Int_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInt_Type" ); + ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); +# endif +# if PY_MAJOR_VERSION >= 3 + ptr__Bytes_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBytes_Type" ); +# endif + } + catch( GetAddressException &e ) + { + OutputDebugStringA( python_dll_name ); + OutputDebugStringA( " does not contain symbol " ); + OutputDebugStringA( e.name ); + OutputDebugStringA( "\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_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; } +# if PY_MAJOR_VERSION == 2 +PyObject *_Exc_StandardError() { return ptr__Exc_StandardError; } +# endif +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; } +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; } + +// +// wrap items in Object.h +// +PyObject *_None() { return ptr__PyNone; } + +PyObject *_False() { return ptr__PyFalse; } +PyObject *_True() { return ptr__PyTrue; } + +PyTypeObject *_CFunction_Type() { return ptr__CFunction_Type; } +PyTypeObject *_Complex_Type() { return ptr__Complex_Type; } +PyTypeObject *_Dict_Type() { return ptr__Dict_Type; } +PyTypeObject *_Float_Type() { return ptr__Float_Type; } +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +PyTypeObject *_Function_Type() { return ptr__Function_Type; } +# endif +PyTypeObject *_Bool_Type() { return ptr__Bool_Type; } +PyTypeObject *_List_Type() { return ptr__List_Type; } +PyTypeObject *_Long_Type() { return ptr__Long_Type; } +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +PyTypeObject *_Method_Type() { return ptr__Method_Type; } +# endif +PyTypeObject *_Module_Type() { return ptr__Module_Type; } +PyTypeObject *_Range_Type() { return ptr__Range_Type; } +PyTypeObject *_Slice_Type() { return ptr__Slice_Type; } +PyTypeObject *_TraceBack_Type() { return ptr__TraceBack_Type; } +PyTypeObject *_Tuple_Type() { return ptr__Tuple_Type; } +PyTypeObject *_Type_Type() { return ptr__Type_Type; } +PyTypeObject *_Unicode_Type() { return ptr__Unicode_Type; } +# if PY_MAJOR_VERSION == 2 +PyTypeObject *_String_Type() { return ptr__String_Type; } +PyTypeObject *_Int_Type() { return ptr__Int_Type; } +PyTypeObject *_CObject_Type() { return ptr__CObject_Type; } +# endif +# if PY_MAJOR_VERSION >= 3 +PyTypeObject *_Bytes_Type() { return ptr__Bytes_Type; } +# endif + +// +// wrap the Python Flag variables +// +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +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_VerboseFlag() { return *ptr_Py_VerboseFlag; } +# endif + +char *__Py_PackageContext() { return *ptr__Py_PackageContext; } + +# if 0 +# define Py_INCREF(op) ( \ + _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ + ((PyObject*)(op))->ob_refcnt++) + +# define Py_DECREF(op) \ + if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ + --((PyObject*)(op))->ob_refcnt != 0) \ + _Py_CHECK_REFCNT(op) \ + else \ + _Py_Dealloc((PyObject *)(op)) +# 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 + +//================================================================================ +// +// Map onto Macros +// +//================================================================================ + +// +// Wrap variables as function calls +// +# define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ + PyObject *_Exc_##eclass() { return ::PyExc_##eclass; } + +# if PY_MAJOR_VERSION == 2 +# include "CXX/Python2/cxx_standard_exceptions.hxx" +# else +# include "CXX/Python3/cxx_standard_exceptions.hxx" +# endif + +# undef PYCXX_STANDARD_EXCEPTION + +// +// wrap items in Object.h +// +PyObject *_None() { return &::_Py_NoneStruct; } + +PyObject *_False() { return Py_False; } +PyObject *_True() { return Py_True; } + +PyTypeObject *_CFunction_Type() { return &PyCFunction_Type; } +PyTypeObject *_Complex_Type() { return &PyComplex_Type; } +PyTypeObject *_Dict_Type() { return &PyDict_Type; } +PyTypeObject *_Float_Type() { return &PyFloat_Type; } +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +PyTypeObject *_Function_Type() { return &PyFunction_Type; } +# endif +PyTypeObject *_Bool_Type() { return &PyBool_Type; } +PyTypeObject *_List_Type() { return &PyList_Type; } +PyTypeObject *_Long_Type() { return &PyLong_Type; } +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +PyTypeObject *_Method_Type() { return &PyMethod_Type; } +# endif +PyTypeObject *_Module_Type() { return &PyModule_Type; } +PyTypeObject *_Range_Type() { return &PyRange_Type; } +PyTypeObject *_Slice_Type() { return &PySlice_Type; } +PyTypeObject *_TraceBack_Type() { return &PyTraceBack_Type; } +PyTypeObject *_Tuple_Type() { return &PyTuple_Type; } +PyTypeObject *_Type_Type() { return &PyType_Type; } +PyTypeObject *_Unicode_Type() { return &PyUnicode_Type; } +# if PY_MAJOR_VERSION == 2 +PyTypeObject *_String_Type() { return &PyString_Type; } +PyTypeObject *_Int_Type() { return &PyInt_Type; } +PyTypeObject *_CObject_Type() { return &PyCObject_Type; } +# endif +# if PY_MAJOR_VERSION >= 3 +PyTypeObject *_Bytes_Type() { return &PyBytes_Type; } +# endif + +// +// wrap flags +// +# if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) +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_VerboseFlag() { return Py_VerboseFlag; } +# if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 7 +const char *__Py_PackageContext() { return _Py_PackageContext; } +# else +char *__Py_PackageContext() { return _Py_PackageContext; } +# endif +# endif + +// +// 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/python/cxx/Src/Python2/cxx_exceptions.cxx b/python/cxx/Src/Python2/cxx_exceptions.cxx new file mode 100644 index 0000000..549c456 --- /dev/null +++ b/python/cxx/Src/Python2/cxx_exceptions.cxx @@ -0,0 +1,72 @@ +// +// cxx_exceptions.cxx +// +#include +#include + +#include + +namespace Py +{ +typedef void (*throw_exception_func_t)( void ); + +std::map py_exc_type_to_exc_func; + +void addPythonException( ExtensionExceptionType &py_exc_type, throw_exception_func_t func ) +{ + py_exc_type_to_exc_func.insert( std::make_pair( py_exc_type.ptr(), func ) ); +} + +void addPythonException( PyObject *py_exc_type, throw_exception_func_t func ) +{ + py_exc_type_to_exc_func.insert( std::make_pair( py_exc_type, func ) ); +} + +void ifPyErrorThrowCxxException() +{ + if( PyErr_Occurred() ) + { + PyObject *ptype, *pvalue, *ptrace; + PyErr_Fetch( &ptype, &pvalue, &ptrace ); + PyErr_Restore( ptype, pvalue, ptrace ); + + Object q( ptype ); + + std::map::iterator func = py_exc_type_to_exc_func.find( ptype ); + if( func != py_exc_type_to_exc_func.end() ) + { +#ifdef PYCXX_DEBUG + std::cout << "ifPyErrorThrowCxxException found throwFunc: " << q << std::endl; +#endif + (func->second)(); + } + else + { +#ifdef PYCXX_DEBUG + std::cout << "ifPyErrorThrowCxxException no throwFunc: " << q << std::endl; +#endif + throw Exception(); + } + } +} + +void initExceptions() +{ + static bool init_done = false; + if( init_done ) + { + return; + } + +#define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ + addPythonException( eclass::exceptionType(), eclass::throwFunc ); + +#include + +#undef PYCXX_STANDARD_EXCEPTION + + init_done = true; +} + + +} // end of namespace Py diff --git a/python/cxx/Src/Python2/cxx_extensions.cxx b/python/cxx/Src/Python2/cxx_extensions.cxx new file mode 100644 index 0000000..f6035c8 --- /dev/null +++ b/python/cxx/Src/Python2/cxx_extensions.cxx @@ -0,0 +1,2037 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) 1998 - 2007, The Regents of the University of California +// Produced at the Lawrence Livermore National Laboratory +// All rights reserved. +// +// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The +// full copyright notice is contained in the file COPYRIGHT located at the root +// of the PyCXX distribution. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the disclaimer below. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the +// documentation and/or materials provided with the distribution. +// - Neither the name of the UC/LLNL nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF +// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +//----------------------------------------------------------------------------- +#include "CXX/Extensions.hxx" +#include "CXX/Exception.hxx" + +#include + +#ifdef PYCXX_DEBUG +// +// Functions useful when debugging PyCXX +// +void bpt( void ) +{ +} + +void printRefCount( PyObject *obj ) +{ + std::cout << "RefCount of 0x" << std::hex << reinterpret_cast< unsigned long >( obj ) << std::dec << " is " << Py_REFCNT( obj ) << std::endl; +} +#endif + +namespace Py +{ +#ifdef PYCXX_PYTHON_2TO3 +std::string String::as_std_string( const char *encoding, const char *error ) const +{ + if( isUnicode() ) + { + Bytes encoded( encode( encoding, error ) ); + return encoded.as_std_string(); + } + else + { + return std::string( PyString_AsString( ptr() ), static_cast( PyString_Size( ptr() ) ) ); + } +} + +Bytes String::encode( const char *encoding, const char *error ) const +{ + if( isUnicode() ) + { + return Bytes( PyUnicode_AsEncodedString( ptr(), encoding, error ) ); + } + else + { + return Bytes( PyString_AsEncodedObject( ptr(), encoding, error ) ); + } +} + +#else +std::string String::as_std_string( const char *encoding, const char *error ) const +{ + if( isUnicode() ) + { + String encoded( encode( encoding, error ) ); + return encoded.as_std_string(); + } + else + { + return std::string( PyString_AsString( ptr() ), static_cast( PyString_Size( ptr() ) ) ); + } +} +#endif + +void Object::validate() +{ + // release pointer if not the right type + if( !accepts( p ) ) + { +#if defined( _CPPRTTI ) || defined( __GNUG__ ) + std::string s( "PyCXX: Error creating object of type " ); + s += (typeid( *this )).name(); + + if( p != NULL ) + { + String from_repr = repr(); + s += " from "; + s += from_repr.as_std_string( "utf-8" ); + } + else + { + s += " from (nil)"; + } +#endif + release(); + + // Error message already set + ifPyErrorThrowCxxException(); + + // Better error message if RTTI available +#if defined( _CPPRTTI ) || defined( __GNUG__ ) + throw TypeError( s ); +#else + throw TypeError( "PyCXX: type error." ); +#endif + } +} + +//================================================================================ +// +// Implementation of MethodTable +// +//================================================================================ +PyMethodDef MethodTable::method( const char *method_name, PyCFunction f, int flags, const char *doc ) +{ + PyMethodDef m; + m.ml_name = const_cast( method_name ); + m.ml_meth = f; + m.ml_flags = flags; + m.ml_doc = const_cast( doc ); + return m; +} + +MethodTable::MethodTable() +{ + t.push_back( method( 0, 0, 0, 0 ) ); + mt = NULL; +} + +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 ) + { + Py_ssize_t t1size = t.size(); + mt = new PyMethodDef[ t1size ]; + int j = 0; + for( std::vector::iterator i = t.begin(); i != t.end(); i++ ) + { + mt[ j++ ] = *i; + } + } + return mt; +} + +//================================================================================ +// +// Implementation of ExtensionModule +// +//================================================================================ +ExtensionModuleBase::ExtensionModuleBase( const char *name ) +: m_module_name( name ) +, m_full_module_name( __Py_PackageContext() != NULL ? std::string( __Py_PackageContext() ) : m_module_name ) +, m_method_table() +, m_module( NULL ) +{} + +ExtensionModuleBase::~ExtensionModuleBase() +{} + +const std::string &ExtensionModuleBase::name() const +{ + return m_module_name; +} + +const std::string &ExtensionModuleBase::fullName() const +{ + return m_full_module_name; +} + +class ExtensionModuleBasePtr : public PythonExtension +{ +public: + ExtensionModuleBasePtr( ExtensionModuleBase *_module ) + : module( _module ) + {} + + virtual ~ExtensionModuleBasePtr() + {} + + ExtensionModuleBase *module; +}; + +void ExtensionModuleBase::initialize( const char *module_doc ) +{ + PyObject *module_ptr = new ExtensionModuleBasePtr( this ); + m_module = Py_InitModule4 + ( + const_cast( m_module_name.c_str() ), // name + m_method_table.table(), // methods + const_cast( module_doc ), // docs + module_ptr, // pass to functions as "self" + PYTHON_API_VERSION // API version + ); +} + +Module ExtensionModuleBase::module( void ) const +{ + return Module( m_full_module_name ); +} + +Dict ExtensionModuleBase::moduleDictionary( void ) const +{ + return module().getDict(); +} + +Object ExtensionModuleBase::moduleObject( void ) const +{ + return Object( m_module ); +} + +//================================================================================ +// +// 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 + // +#if defined( PYCXX_PYTHON_2TO3 ) + static int print_handler( PyObject *, FILE *, int ); +#endif + 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 * ); +#if defined( PYCXX_PYTHON_2TO3 ) + static int compare_handler( PyObject *, PyObject * ); +#endif + static PyObject *rich_compare_handler( PyObject *, PyObject *, int ); + static PyObject *repr_handler( PyObject * ); + static PyObject *str_handler( PyObject * ); + static long hash_handler( PyObject * ); + static PyObject *call_handler( PyObject *, PyObject *, PyObject * ); + static PyObject *iter_handler( PyObject * ); + static PyObject *iternext_handler( PyObject * ); + + // 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 * ); + + static PyObject *sequence_inplace_concat_handler( PyObject *, PyObject * ); + static PyObject *sequence_inplace_repeat_handler( PyObject *, Py_ssize_t ); + + static int sequence_contains_handler( PyObject *, 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 ); +} + +bool PythonType::readyType() +{ + return PyType_Ready( table ) >= 0; +} + +PythonType &PythonType::supportSequenceType( int methods_to_support ) +{ + if( !sequence_table ) + { + sequence_table = new PySequenceMethods; + memset( sequence_table, 0, sizeof( PySequenceMethods ) ); // ensure new fields are 0 + table->tp_as_sequence = sequence_table; + if( methods_to_support&support_sequence_length ) + { + sequence_table->sq_length = sequence_length_handler; + } + if( methods_to_support&support_sequence_repeat ) + { + sequence_table->sq_repeat = sequence_repeat_handler; + } + if( methods_to_support&support_sequence_item ) + { + sequence_table->sq_item = sequence_item_handler; + } + if( methods_to_support&support_sequence_slice ) + { + sequence_table->sq_slice = sequence_slice_handler; + } + if( methods_to_support&support_sequence_concat ) + { + sequence_table->sq_concat = sequence_concat_handler; + } + if( methods_to_support&support_sequence_ass_item ) + { + sequence_table->sq_ass_item = sequence_ass_item_handler; + } + if( methods_to_support&support_sequence_ass_slice ) + { + sequence_table->sq_ass_slice = sequence_ass_slice_handler; + } + if( methods_to_support&support_sequence_inplace_concat ) + { + sequence_table->sq_inplace_concat = sequence_inplace_concat_handler; + } + if( methods_to_support&support_sequence_inplace_repeat ) + { + sequence_table->sq_inplace_repeat = sequence_inplace_repeat_handler; + } + if( methods_to_support&support_sequence_contains ) + { + sequence_table->sq_contains = sequence_contains_handler; + } + } + return *this; +} + + +PythonType &PythonType::supportMappingType( int methods_to_support ) +{ + if( !mapping_table ) + { + mapping_table = new PyMappingMethods; + memset( mapping_table, 0, sizeof( PyMappingMethods ) ); // ensure new fields are 0 + table->tp_as_mapping = mapping_table; + + if( methods_to_support&support_mapping_length ) + { + mapping_table->mp_length = mapping_length_handler; + } + if( methods_to_support&support_mapping_subscript ) + { + mapping_table->mp_subscript = mapping_subscript_handler; + } + if( methods_to_support&support_mapping_ass_subscript ) + { + mapping_table->mp_ass_subscript = mapping_ass_subscript_handler; + } + } + return *this; +} + +PythonType &PythonType::supportNumberType( int methods_to_support ) +{ + if( !number_table ) + { + number_table = new PyNumberMethods; + memset( number_table, 0, sizeof( PyNumberMethods ) ); // ensure new fields are 0 + table->tp_as_number = number_table; + number_table->nb_coerce = 0; + + if( methods_to_support&support_number_add ) + { + number_table->nb_add = number_add_handler; + } + if( methods_to_support&support_number_subtract ) + { + number_table->nb_subtract = number_subtract_handler; + } + if( methods_to_support&support_number_multiply ) + { + number_table->nb_multiply = number_multiply_handler; + } + if( methods_to_support&support_number_divide ) + { + number_table->nb_divide = number_divide_handler; + } + if( methods_to_support&support_number_remainder ) + { + number_table->nb_remainder = number_remainder_handler; + } + if( methods_to_support&support_number_divmod ) + { + number_table->nb_divmod = number_divmod_handler; + } + if( methods_to_support&support_number_power ) + { + number_table->nb_power = number_power_handler; + } + if( methods_to_support&support_number_negative ) + { + number_table->nb_negative = number_negative_handler; + } + if( methods_to_support&support_number_positive ) + { + number_table->nb_positive = number_positive_handler; + } + if( methods_to_support&support_number_absolute ) + { + number_table->nb_absolute = number_absolute_handler; + } + if( methods_to_support&support_number_nonzero ) + { + number_table->nb_nonzero = number_nonzero_handler; + } + if( methods_to_support&support_number_invert ) + { + number_table->nb_invert = number_invert_handler; + } + if( methods_to_support&support_number_lshift ) + { + number_table->nb_lshift = number_lshift_handler; + } + if( methods_to_support&support_number_rshift ) + { + number_table->nb_rshift = number_rshift_handler; + } + if( methods_to_support&support_number_and ) + { + number_table->nb_and = number_and_handler; + } + if( methods_to_support&support_number_xor ) + { + number_table->nb_xor = number_xor_handler; + } + if( methods_to_support&support_number_or ) + { + number_table->nb_or = number_or_handler; + } + if( methods_to_support&support_number_int ) + { + number_table->nb_int = number_int_handler; + } + if( methods_to_support&support_number_long ) + { + number_table->nb_long = number_long_handler; + } + if( methods_to_support&support_number_float ) + { + number_table->nb_float = number_float_handler; + } + if( methods_to_support&support_number_oct ) + { + number_table->nb_oct = number_oct_handler; + } + if( methods_to_support&support_number_hex ) + { + number_table->nb_hex = number_hex_handler; + } + } + return *this; +} + +PythonType &PythonType::supportBufferType( int methods_to_support ) +{ + if( !buffer_table ) + { + buffer_table = new PyBufferProcs; + memset( buffer_table, 0, sizeof( PyBufferProcs ) ); // ensure new fields are 0 + table->tp_as_buffer = buffer_table; + + if( methods_to_support&support_buffer_getreadbuffer ) + { + buffer_table->bf_getreadbuffer = buffer_getreadbuffer_handler; + } + if( methods_to_support&support_buffer_getwritebuffer ) + { + buffer_table->bf_getwritebuffer = buffer_getwritebuffer_handler; + } + if( methods_to_support&support_buffer_getsegcount ) + { + buffer_table->bf_getsegcount = buffer_getsegcount_handler; + } + } + return *this; +} + +// +// if you define add methods that you hook. Use the hook_XXX to choice what to hook. +// +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 ) +{ + // PyTypeObject is defined in /Include/object.h + + memset( table, 0, sizeof( PyTypeObject ) ); // ensure new fields are 0 + *reinterpret_cast( table ) = py_object_initializer; + table->ob_type = _Type_Type(); + table->ob_size = 0; + + table->tp_name = const_cast( default_name ); + table->tp_basicsize = basic_size; + table->tp_itemsize = itemsize; + + // Methods to implement standard operations + 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; + + // Method suites for standard classes + table->tp_as_number = 0; + table->tp_as_sequence = 0; + table->tp_as_mapping = 0; + + // More standard operations (here for binary compatibility) + table->tp_hash = 0; + table->tp_call = 0; + table->tp_str = 0; + table->tp_getattro = 0; + table->tp_setattro = 0; + + // Functions to access object as input/output buffer + table->tp_as_buffer = 0; + + // Flags to define presence of optional/expanded features + table->tp_flags = Py_TPFLAGS_DEFAULT; + + // Documentation string + table->tp_doc = 0; + +#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 0) + table->tp_traverse = 0L; + + // delete references to contained objects + 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; + // weak reference enabler + table->tp_weaklistoffset = 0L; +#else + table->tp_xxx7 = 0L; + table->tp_xxx8 = 0L; +#endif +#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 2) + // first defined in 2.3 + // Iterators + table->tp_iter = 0L; + table->tp_iternext = 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; +} + +PythonType &PythonType::name( const char *nam ) +{ + table->tp_name = const_cast( nam ); + return *this; +} + +const char *PythonType::getName() const +{ + return table->tp_name; +} + +PythonType &PythonType::doc( const char *d ) +{ + table->tp_doc = const_cast( d ); + return *this; +} + +const char *PythonType::getDoc() const +{ + return table->tp_doc; +} + +PythonType &PythonType::set_tp_dealloc( void (*tp_dealloc)( PyObject *self ) ) +{ + table->tp_dealloc = tp_dealloc; + return *this; +} + +PythonType &PythonType::set_tp_init( int (*tp_init)( PyObject *self, PyObject *args, PyObject *kwds ) ) +{ + table->tp_init = tp_init; + return *this; +} + +PythonType &PythonType::set_tp_new( PyObject *(*tp_new)( PyTypeObject *subtype, PyObject *args, PyObject *kwds ) ) +{ + table->tp_new = tp_new; + return *this; +} + +PythonType &PythonType::set_methods( PyMethodDef *methods ) +{ + table->tp_methods = methods; + return *this; +} + +PythonType &PythonType::supportClass() +{ + table->tp_flags |= Py_TPFLAGS_BASETYPE; + return *this; +} + +PythonType &PythonType::dealloc( void( *f )( PyObject * )) +{ + table->tp_dealloc = f; + return *this; +} + +#if defined( PYCXX_PYTHON_2TO3 ) +PythonType &PythonType::supportPrint() +{ + table->tp_print = print_handler; + return *this; +} +#endif + +PythonType &PythonType::supportGetattr() +{ + table->tp_getattr = getattr_handler; + return *this; +} + +PythonType &PythonType::supportSetattr() +{ + table->tp_setattr = setattr_handler; + return *this; +} + +PythonType &PythonType::supportGetattro() +{ + table->tp_getattro = getattro_handler; + return *this; +} + +PythonType &PythonType::supportSetattro() +{ + table->tp_setattro = setattro_handler; + return *this; +} + +#if defined( PYCXX_PYTHON_2TO3 ) +PythonType &PythonType::supportCompare() +{ + table->tp_compare = compare_handler; + return *this; +} +#endif + +#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) +PythonType &PythonType::supportRichCompare() +{ + table->tp_richcompare = rich_compare_handler; + return *this; +} +#endif + +PythonType &PythonType::supportRepr() +{ + table->tp_repr = repr_handler; + return *this; +} + +PythonType &PythonType::supportStr() +{ + table->tp_str = str_handler; + return *this; +} + +PythonType &PythonType::supportHash() +{ + table->tp_hash = hash_handler; + return *this; +} + +PythonType &PythonType::supportCall() +{ + table->tp_call = call_handler; + return *this; +} + +PythonType &PythonType::supportIter( int methods_to_support ) +{ + if( methods_to_support&support_iter_iter ) + { + table->tp_iter = iter_handler; + } + if( methods_to_support&support_iter_iternext ) + { + table->tp_iternext = iternext_handler; + } + return *this; +} + +//-------------------------------------------------------------------------------- +// +// Handlers +// +//-------------------------------------------------------------------------------- +PythonExtensionBase *getPythonExtensionBase( PyObject *self ) +{ + if( self->ob_type->tp_flags&Py_TPFLAGS_BASETYPE ) + { + PythonClassInstance *instance = reinterpret_cast( self ); + return instance->m_pycxx_object; + } + else + { + return static_cast( self ); + } +} + + +#if defined( PYCXX_PYTHON_2TO3 ) +extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->print( fp, flags ); + } + catch( BaseException &) + { + return -1; // indicate error + } +} +#endif + +extern "C" PyObject *getattr_handler( PyObject *self, char *name ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->getattr( name ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" int setattr_handler( PyObject *self, char *name, PyObject *value ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->setattr( name, Object( value ) ); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +extern "C" PyObject *getattro_handler( PyObject *self, PyObject *name ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->getattro( String( name ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" int setattro_handler( PyObject *self, PyObject *name, PyObject *value ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->setattro( String( name ), Object( value ) ); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +#if defined( PYCXX_PYTHON_2TO3 ) +extern "C" int compare_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->compare( Object( other ) ); + } + catch( BaseException &) + { + return -1; // indicate error + } +} +#endif + +#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) +extern "C" PyObject *rich_compare_handler( PyObject *self, PyObject *other, int op ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->rich_compare( Object( other ), op ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} +#endif + +extern "C" PyObject *repr_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->repr() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *str_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->str() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" long hash_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->hash(); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +extern "C" PyObject *call_handler( PyObject *self, PyObject *args, PyObject *kw ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + if( kw != NULL ) + return new_reference_to( p->call( Object( args ), Object( kw ) ) ); + else + return new_reference_to( p->call( Object( args ), Object() ) ); + } + + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *iter_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->iter() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *iternext_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->iternext(); // might be a NULL ptr on end of iteration + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +// Sequence methods +extern "C" Py_ssize_t sequence_length_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->sequence_length(); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +extern "C" PyObject *sequence_concat_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->sequence_concat( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *sequence_repeat_handler( PyObject *self, Py_ssize_t count ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->sequence_repeat( count ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *sequence_item_handler( PyObject *self, Py_ssize_t index ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->sequence_item( index ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *sequence_slice_handler( PyObject *self, Py_ssize_t first, Py_ssize_t last ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->sequence_slice( first, last ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" int sequence_ass_item_handler( PyObject *self, Py_ssize_t index, PyObject *value ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->sequence_ass_item( index, Object( value ) ); + } + catch( BaseException &) + { + 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 = getPythonExtensionBase( self ); + return p->sequence_ass_slice( first, last, Object( value ) ); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +extern "C" PyObject *sequence_inplace_concat_handler( PyObject *self, PyObject *o2 ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->sequence_inplace_concat( Object( o2 ) ) ); + } + catch( BaseException & ) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *sequence_inplace_repeat_handler( PyObject *self, Py_ssize_t count ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->sequence_inplace_repeat( count ) ); + } + catch( BaseException & ) + { + return NULL; // indicate error + } +} + +extern "C" int sequence_contains_handler( PyObject *self, PyObject *value ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->sequence_contains( Object( value ) ); + } + catch( BaseException & ) + { + return -1; // indicate error + } +} + +// Mapping +extern "C" Py_ssize_t mapping_length_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->mapping_length(); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +extern "C" PyObject *mapping_subscript_handler( PyObject *self, PyObject *key ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->mapping_subscript( Object( key ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" int mapping_ass_subscript_handler( PyObject *self, PyObject *key, PyObject *value ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->mapping_ass_subscript( Object( key ), Object( value ) ); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +// Number +extern "C" int number_nonzero_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->number_nonzero(); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +extern "C" PyObject *number_negative_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_negative() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_positive_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_positive() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_absolute_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_absolute() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_invert_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_invert() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_int_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_int() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_float_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_float() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_long_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_long() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_oct_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_oct() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_hex_handler( PyObject *self ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_hex() ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_add_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_add( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_subtract_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_subtract( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_multiply_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_multiply( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_divide_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_divide( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_remainder_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_remainder( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_divmod_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_divmod( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_lshift_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_lshift( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_rshift_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_rshift( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_and_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_and( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_xor_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_xor( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_or_handler( PyObject *self, PyObject *other ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_or( Object( other ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +extern "C" PyObject *number_power_handler( PyObject *self, PyObject *x1, PyObject *x2 ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return new_reference_to( p->number_power( Object( x1 ), Object( x2 ) ) ); + } + catch( BaseException &) + { + return NULL; // indicate error + } +} + +// Buffer +extern "C" Py_ssize_t buffer_getreadbuffer_handler( PyObject *self, Py_ssize_t index, void **pp ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->buffer_getreadbuffer( index, pp ); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +extern "C" Py_ssize_t buffer_getwritebuffer_handler( PyObject *self, Py_ssize_t index, void **pp ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->buffer_getwritebuffer( index, pp ); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +extern "C" Py_ssize_t buffer_getsegcount_handler( PyObject *self, Py_ssize_t *count ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->buffer_getsegcount( count ); + } + catch( BaseException &) + { + return -1; // indicate error + } +} + +//================================================================================ +// +// Implementation of PythonExtensionBase +// +//================================================================================ +#define missing_method( method ) \ + throw RuntimeError( "Extension object missing implement of " #method ); + +PythonExtensionBase::PythonExtensionBase() +{ + ob_refcnt = 0; +} + +PythonExtensionBase::~PythonExtensionBase() +{ + assert( ob_refcnt == 0 ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name ) +{ + TupleN args; + return self().callMemberFunction( fn_name, args ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Object &arg1 ) +{ + TupleN args( arg1 ); + return self().callMemberFunction( fn_name, args ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2 ) +{ + TupleN args( arg1, arg2 ); + return self().callMemberFunction( fn_name, args ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3 ) +{ + TupleN args( arg1, arg2, arg3 ); + return self().callMemberFunction( fn_name, args ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4 ) +{ + TupleN args( arg1, arg2, arg3, arg4 ); + return self().callMemberFunction( fn_name, args ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5 ) +{ + TupleN args( arg1, arg2, arg3, arg4, arg5 ); + return self().callMemberFunction( fn_name, args ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6 ) +{ + TupleN args( arg1, arg2, arg3, arg4, arg5, arg6 ); + return self().callMemberFunction( fn_name, args ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7 ) +{ + TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); + return self().callMemberFunction( fn_name, args ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7, const Object &arg8 ) +{ + TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); + return self().callMemberFunction( fn_name, args ); +} + +Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7, const Object &arg8, const Object &arg9 ) +{ + TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); + return self().callMemberFunction( fn_name, args ); +} + +void PythonExtensionBase::reinit( Tuple &/*args*/, Dict &/*kwds*/ ) +{ + throw RuntimeError( "Must not call __init__ twice on this class" ); +} + +Object PythonExtensionBase::genericGetAttro( const String &name ) +{ + return asObject( PyObject_GenericGetAttr( selfPtr(), name.ptr() ) ); +} + +int PythonExtensionBase::genericSetAttro( const String &name, const Object &value ) +{ + return PyObject_GenericSetAttr( selfPtr(), name.ptr(), value.ptr() ); +} + +int PythonExtensionBase::print( FILE *, int ) +{ + missing_method( print ); +} + +Object PythonExtensionBase::getattr( const char * ) +{ + missing_method( getattr ); +} + +int PythonExtensionBase::setattr( const char *, const Object &) +{ + missing_method( setattr ); +} + +Object PythonExtensionBase::getattro( const String &name ) +{ + return genericGetAttro( name ); +} + +int PythonExtensionBase::setattro( const String &name, const Object &value ) +{ + return genericSetAttro( name, value ); +} + +int PythonExtensionBase::compare( const Object &) +{ + missing_method( compare ); +} + +#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) +Object PythonExtensionBase::rich_compare( const Object &, int /*op*/ ) +{ + missing_method( rich_compare ); +} + +#endif +Object PythonExtensionBase::repr() +{ + missing_method( repr ); +} + +Object PythonExtensionBase::str() +{ + missing_method( str ); +} + +long PythonExtensionBase::hash() +{ + missing_method( hash ); +} + +Object PythonExtensionBase::call( const Object &, const Object &) +{ + missing_method( call ); +} + +Object PythonExtensionBase::iter() +{ + missing_method( iter ); +} + +PyObject *PythonExtensionBase::iternext() +{ + missing_method( iternext ); +} + +// Sequence methods +PyCxx_ssize_t PythonExtensionBase::sequence_length() +{ + missing_method( sequence_length ); +} + +Object PythonExtensionBase::sequence_concat( const Object &) +{ + missing_method( sequence_concat ); +} + +Object PythonExtensionBase::sequence_repeat( Py_ssize_t ) +{ + missing_method( sequence_repeat ); +} + +Object PythonExtensionBase::sequence_item( Py_ssize_t ) +{ + missing_method( sequence_item ); +} + +Object PythonExtensionBase::sequence_slice( Py_ssize_t, Py_ssize_t ) +{ + missing_method( sequence_slice ); +} + +int PythonExtensionBase::sequence_ass_item( Py_ssize_t, const Object &) +{ + missing_method( sequence_ass_item ); +} + +int PythonExtensionBase::sequence_ass_slice( Py_ssize_t, Py_ssize_t, const Object &) +{ + missing_method( sequence_ass_slice ); +} + +Object PythonExtensionBase::sequence_inplace_concat( const Object & ) +{ + missing_method( sequence_inplace_concat ); +} + +Object PythonExtensionBase::sequence_inplace_repeat( Py_ssize_t ) +{ + missing_method( sequence_inplace_repeat ); +} + +int PythonExtensionBase::sequence_contains( const Object & ) +{ + missing_method( sequence_contains ); +} + +// Mapping +Sequence::size_type PythonExtensionBase::mapping_length() +{ + missing_method( mapping_length ); +} + +Object PythonExtensionBase::mapping_subscript( const Object &) +{ + missing_method( mapping_subscript ); +} + +int PythonExtensionBase::mapping_ass_subscript( const Object &, const Object &) +{ + missing_method( mapping_ass_subscript ); +} + +// Number +int PythonExtensionBase::number_nonzero() +{ + missing_method( number_nonzero ); +} + +Object PythonExtensionBase::number_negative() +{ + missing_method( number_negative ); +} + +Object PythonExtensionBase::number_positive() +{ + missing_method( number_positive ); +} + +Object PythonExtensionBase::number_absolute() +{ + missing_method( number_absolute ); +} + +Object PythonExtensionBase::number_invert() +{ + missing_method( number_invert ); +} + +Object PythonExtensionBase::number_int() +{ + missing_method( number_int ); +} + +Object PythonExtensionBase::number_float() +{ + missing_method( number_float ); +} + +Object PythonExtensionBase::number_long() +{ + missing_method( number_long ); +} + +Object PythonExtensionBase::number_oct() +{ + missing_method( number_oct ); +} + +Object PythonExtensionBase::number_hex() +{ + missing_method( number_hex ); +} + +Object PythonExtensionBase::number_add( const Object &) +{ + missing_method( number_add ); +} + +Object PythonExtensionBase::number_subtract( const Object &) +{ + missing_method( number_subtract ); +} + +Object PythonExtensionBase::number_multiply( const Object &) +{ + missing_method( number_multiply ); +} + +Object PythonExtensionBase::number_divide( const Object &) +{ + missing_method( number_divide ); +} + +Object PythonExtensionBase::number_remainder( const Object &) +{ + missing_method( number_remainder ); +} + +Object PythonExtensionBase::number_divmod( const Object &) +{ + missing_method( number_divmod ); +} + +Object PythonExtensionBase::number_lshift( const Object &) +{ + missing_method( number_lshift ); +} + +Object PythonExtensionBase::number_rshift( const Object &) +{ + missing_method( number_rshift ); +} + +Object PythonExtensionBase::number_and( const Object &) +{ + missing_method( number_and ); +} + +Object PythonExtensionBase::number_xor( const Object &) +{ + missing_method( number_xor ); +} + +Object PythonExtensionBase::number_or( const Object &) +{ + missing_method( number_or ); +} + +Object PythonExtensionBase::number_power( const Object &, const Object &) +{ + missing_method( number_power ); +} + +// Buffer +Py_ssize_t PythonExtensionBase::buffer_getreadbuffer( Py_ssize_t, void** ) +{ + missing_method( buffer_getreadbuffer ); +} + +Py_ssize_t PythonExtensionBase::buffer_getwritebuffer( Py_ssize_t, void** ) +{ + missing_method( buffer_getwritebuffer ); +} + +Py_ssize_t PythonExtensionBase::buffer_getsegcount( Py_ssize_t* ) +{ + missing_method( buffer_getsegcount ); +} + +//-------------------------------------------------------------------------------- +// +// Method call handlers for +// PythonExtensionBase +// ExtensionModuleBase +// +//-------------------------------------------------------------------------------- +extern "C" PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ) +{ + 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( self_as_void ); + + Object result( self->invoke_method_noargs( PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ) ); + + return new_reference_to( result.ptr() ); + } + catch( BaseException & ) + { + 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( self_as_void ); + Tuple args( _args ); + + Object result + ( + self->invoke_method_varargs + ( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + args + ) + ); + + return new_reference_to( result.ptr() ); + } + catch( BaseException & ) + { + return 0; + } +} + +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( self_as_void ); + + Tuple args( _args ); + + if( _keywords == NULL ) + { + Dict keywords; // pass an empty dict + + Object result + ( + self->invoke_method_keyword + ( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + args, + keywords + ) + ); + + return new_reference_to( result.ptr() ); + } + else + { + Dict keywords( _keywords ); // make dict + + Object result + ( + self->invoke_method_keyword + ( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + args, + keywords + ) + ); + + return new_reference_to( result.ptr() ); + } + } + catch( BaseException & ) + { + return 0; + } +} + + +extern "C" void do_not_dealloc( void * ) +{} + +//-------------------------------------------------------------------------------- +// +// ExtensionExceptionType +// +//-------------------------------------------------------------------------------- +ExtensionExceptionType::ExtensionExceptionType() +: 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( module_name.c_str() ), NULL, NULL ), true ); +} + +void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::string& name, ExtensionExceptionType &parent) +{ + std::string module_name( module.fullName() ); + module_name += "."; + module_name += name; + set( PyErr_NewException( const_cast( module_name.c_str() ), parent.ptr(), NULL ), true ); +} + +ExtensionExceptionType::~ExtensionExceptionType() +{ +} + +// ------------------------------------------------------------ +// +// BaseException +// +//------------------------------------------------------------ +BaseException::BaseException( ExtensionExceptionType &exception, const std::string &reason ) +{ + PyErr_SetString( exception.ptr(), reason.c_str() ); +} + +BaseException::BaseException( ExtensionExceptionType &exception, Object &reason ) +{ + PyErr_SetObject( exception.ptr(), reason.ptr() ); +} + +BaseException::BaseException( PyObject *exception, Object &reason ) +{ + PyErr_SetObject( exception, reason.ptr() ); +} + +BaseException::BaseException( PyObject *exception, const std::string &reason ) +{ + PyErr_SetString( exception, reason.c_str() ); +} + +BaseException::BaseException() +{} + +void BaseException::clear() +{ + PyErr_Clear(); +} + +bool BaseException::matches( ExtensionExceptionType &exc ) +// is the exception this specific exception 'exc' +{ + return PyErr_ExceptionMatches( exc.ptr() ) != 0; +} + +} // end of namespace Py diff --git a/python/cxx/cxxextensions.c b/python/cxx/Src/Python2/cxxextensions.c similarity index 98% copy from python/cxx/cxxextensions.c copy to python/cxx/Src/Python2/cxxextensions.c index 19eadd9..edae3be 100644 --- a/python/cxx/cxxextensions.c +++ b/python/cxx/Src/Python2/cxxextensions.c @@ -1,49 +1,49 @@ /*---------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //---------------------------------------------------------------------------*/ -#include "WrapPython.h" +#include "CXX/WrapPython.h" #ifdef __cplusplus extern "C" { #endif PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; #ifdef __cplusplus } #endif diff --git a/python/cxx/cxxsupport.cxx b/python/cxx/Src/Python2/cxxsupport.cxx similarity index 97% rename from python/cxx/cxxsupport.cxx rename to python/cxx/Src/Python2/cxxsupport.cxx index 23963cc..1dfba5a 100644 --- a/python/cxx/cxxsupport.cxx +++ b/python/cxx/Src/Python2/cxxsupport.cxx @@ -1,178 +1,174 @@ //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- -#include "Objects.hxx" +#include "CXX/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 { -#ifdef Py_USING_UNICODE - if( Py::_Unicode_Check(p) ) - return String (PyObject_Unicode (p), true); -#endif 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(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(ob.str())); } #endif } // Py diff --git a/python/cxx/Src/cxx_exceptions.cxx b/python/cxx/Src/cxx_exceptions.cxx new file mode 100644 index 0000000..60e8767 --- /dev/null +++ b/python/cxx/Src/cxx_exceptions.cxx @@ -0,0 +1,7 @@ +#include "CXX/WrapPython.h" + +#if PY_MAJOR_VERSION == 2 +#include "Python2/cxx_exceptions.cxx" +#else +#include "Python3/cxx_exceptions.cxx" +#endif diff --git a/python/cxx/cxxextensions.c b/python/cxx/Src/cxx_extensions.cxx similarity index 89% copy from python/cxx/cxxextensions.c copy to python/cxx/Src/cxx_extensions.cxx index 19eadd9..898c9f4 100644 --- a/python/cxx/cxxextensions.c +++ b/python/cxx/Src/cxx_extensions.cxx @@ -1,49 +1,43 @@ -/*---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // -//---------------------------------------------------------------------------*/ +//----------------------------------------------------------------------------- +#include "CXX/WrapPython.h" -#include "WrapPython.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; - -#ifdef __cplusplus -} +#if PY_MAJOR_VERSION == 2 +#include "Python2/cxx_extensions.cxx" +#else +#include "Python3/cxx_extensions.cxx" #endif diff --git a/python/cxx/cxxextensions.c b/python/cxx/Src/cxxextensions.c similarity index 89% copy from python/cxx/cxxextensions.c copy to python/cxx/Src/cxxextensions.c index 19eadd9..28a8e1d 100644 --- a/python/cxx/cxxextensions.c +++ b/python/cxx/Src/cxxextensions.c @@ -1,49 +1,43 @@ -/*---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // -//---------------------------------------------------------------------------*/ +//----------------------------------------------------------------------------- +#include "CXX/WrapPython.h" -#include "WrapPython.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; - -#ifdef __cplusplus -} +#if PY_MAJOR_VERSION == 2 +#include "Src/Python2/cxxextensions.c" +#else +#include "Src/Python3/cxxextensions.c" #endif diff --git a/python/cxx/cxxextensions.c b/python/cxx/Src/cxxsupport.cxx similarity index 89% rename from python/cxx/cxxextensions.c rename to python/cxx/Src/cxxsupport.cxx index 19eadd9..1f2fb43 100644 --- a/python/cxx/cxxextensions.c +++ b/python/cxx/Src/cxxsupport.cxx @@ -1,49 +1,43 @@ -/*---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // -//---------------------------------------------------------------------------*/ +//----------------------------------------------------------------------------- +#include "CXX/WrapPython.h" -#include "WrapPython.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; - -#ifdef __cplusplus -} +#if PY_MAJOR_VERSION == 2 +#include "Src/Python2/cxxsupport.cxx" +#else +#include "Src/Python3/cxxsupport.cxx" #endif diff --git a/python/cxx/WrapPython.h b/python/cxx/WrapPython.h deleted file mode 100644 index 16c5502..0000000 --- a/python/cxx/WrapPython.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -Copyright (c) 1998 - 2007, The Regents of the University of California -Produced at the Lawrence Livermore National Laboratory -All rights reserved. - -This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The -full copyright notice is contained in the file COPYRIGHT located at the root -of the PyCXX distribution. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - - Redistributions of source code must retain the above copyright notice, - this list of conditions and the disclaimer below. - - Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the disclaimer (as noted below) in the - documentation and/or materials provided with the distribution. - - Neither the name of the UC/LLNL nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF -CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef __PyCXX_wrap_python_hxx__ -#define __PyCXX_wrap_python_hxx__ - -/* On some platforms we have to include time.h to get select defined */ -#if !defined(__WIN32__) && !defined(WIN32) && !defined(_WIN32) && !defined(_WIN64) -#include -#endif - -/* Prevent warnings */ -#if defined(_XOPEN_SOURCE) - #undef _XOPEN_SOURCE -#endif -#if defined(_POSIX_C_SOURCE) - #undef _POSIX_C_SOURCE -#endif - -/* Prevent multiple conflicting definitions of swab from stdlib.h and unistd.h -See also http://bugs.kde.org/show_bug.cgi?id=156950 */ -#if defined(__sun) || defined(sun) - #if defined(_XPG4) - #undef _XPG4 - #endif -#endif - -/* pull in python definitions */ -#include - -#endif diff --git a/python/cxx/cxx_extensions.cxx b/python/cxx/cxx_extensions.cxx deleted file mode 100644 index 58453e6..0000000 --- a/python/cxx/cxx_extensions.cxx +++ /dev/null @@ -1,1400 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (c) 1998 - 2007, The Regents of the University of California -// Produced at the Lawrence Livermore National Laboratory -// All rights reserved. -// -// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The -// full copyright notice is contained in the file COPYRIGHT located at the root -// of the PyCXX distribution. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the disclaimer below. -// - Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the -// documentation and/or materials provided with the distribution. -// - Neither the name of the UC/LLNL nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF -// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -//----------------------------------------------------------------------------- -#include "Extensions.hxx" -#include "Exception.hxx" - -#include - -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( method_name ); - m.ml_meth = f; - m.ml_flags = flags; - m.ml_doc = const_cast( 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 ) - { - Py_ssize_t t1size = t.size(); - mt = new PyMethodDef[t1size]; - int j = 0; - for( std::vector::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 -{ -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( module_name.c_str() ), // name - method_table.table(), // methods - const_cast( 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*); - static PyObject* iter_handler (PyObject*); - static PyObject* iternext_handler (PyObject*); - - // 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 ); -} - -PythonType & PythonType::supportSequenceType() -{ - if( !sequence_table ) - { - sequence_table = new PySequenceMethods; - memset( sequence_table, 0, sizeof( PySequenceMethods ) ); // ensure new fields are 0 - 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 separately? - sequence_table->sq_ass_slice = sequence_ass_slice_handler; // BAS setup separately? - } - return *this; -} - -PythonType & PythonType::supportMappingType() -{ - if( !mapping_table ) - { - mapping_table = new PyMappingMethods; - memset( mapping_table, 0, sizeof( PyMappingMethods ) ); // ensure new fields are 0 - 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 separately? - } - return *this; -} - -PythonType & PythonType::supportNumberType() -{ - if( !number_table ) - { - number_table = new PyNumberMethods; - memset( number_table, 0, sizeof( PyNumberMethods ) ); // ensure new fields are 0 - 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; - } - return *this; -} - -PythonType & PythonType::supportBufferType() -{ - if( !buffer_table ) - { - buffer_table = new PyBufferProcs; - memset( buffer_table, 0, sizeof( PyBufferProcs ) ); // ensure new fields are 0 - 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; - } - return *this; -} - -// 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 ) -{ - memset( table, 0, sizeof( PyTypeObject ) ); // ensure new fields are 0 - *reinterpret_cast( table ) = py_object_initializer; - table->ob_type = _Type_Type(); - table->ob_size = 0; - table->tp_name = const_cast( 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 = Py_TPFLAGS_DEFAULT; - 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 - -#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 2) - // first defined in 2.3 - table->tp_iter = 0L; - table->tp_iternext = 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;} - -PythonType & PythonType::name( const char* nam ) -{ - table->tp_name = const_cast( nam ); - return *this; -} - -const char *PythonType::getName() const -{ - return table->tp_name; -} - -PythonType & PythonType::doc( const char* d ) -{ - table->tp_doc = const_cast( d ); - return *this; -} - -const char *PythonType::getDoc() const -{ - return table->tp_doc; -} - -PythonType & PythonType::dealloc( void( *f )( PyObject* )) -{ - table->tp_dealloc = f; - return *this; -} - -PythonType & PythonType::supportPrint() -{ - table->tp_print = print_handler; - return *this; -} - -PythonType & PythonType::supportGetattr() -{ - table->tp_getattr = getattr_handler; - return *this; -} - -PythonType & PythonType::supportSetattr() -{ - table->tp_setattr = setattr_handler; - return *this; -} - -PythonType & PythonType::supportGetattro() -{ - table->tp_getattro = getattro_handler; - return *this; -} - -PythonType & PythonType::supportSetattro() -{ - table->tp_setattro = setattro_handler; - return *this; -} - -PythonType & PythonType::supportCompare() -{ - table->tp_compare = compare_handler; - return *this; -} - -PythonType & PythonType::supportRepr() -{ - table->tp_repr = repr_handler; - return *this; -} - -PythonType & PythonType::supportStr() -{ - table->tp_str = str_handler; - return *this; -} - -PythonType & PythonType::supportHash() -{ - table->tp_hash = hash_handler; - return *this; -} - -PythonType & PythonType::supportCall() -{ - table->tp_call = call_handler; - return *this; -} - -PythonType & PythonType::supportIter() -{ - table->tp_iter = iter_handler; - table->tp_iternext = iternext_handler; - return *this; -} - -//-------------------------------------------------------------------------------- -// -// Handlers -// -//-------------------------------------------------------------------------------- -extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) -{ - try - { - PythonExtensionBase *p = static_cast( 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( 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( 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( 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( 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( 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( 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( 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( 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( self ); - 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 - } -} - -extern "C" PyObject* iter_handler( PyObject *self ) -{ - try - { - PythonExtensionBase *p = static_cast( self ); - return new_reference_to( p->iter() ); - } - catch( Py::Exception & ) - { - return NULL; // indicate error - } -} - -extern "C" PyObject* iternext_handler( PyObject *self ) -{ - try - { - PythonExtensionBase *p = static_cast( self ); - return p->iternext(); // might be a NULL ptr on end of iteration - } - catch( Py::Exception & ) - { - return NULL; // indicate error - } -} - - -// Sequence methods -extern "C" Py_ssize_t sequence_length_handler( PyObject *self ) -{ - try - { - PythonExtensionBase *p = static_cast( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( self ); - return p->buffer_getsegcount( count ); - } - 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(); } - -Py::Object PythonExtensionBase::iter() -{ missing_method( iter ); return Py::Nothing(); } - -PyObject* PythonExtensionBase::iternext() -{ missing_method( iternext ); return NULL; } - - -// 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( Py_ssize_t ) -{ missing_method( sequence_repeat ); return Py::Nothing(); } - -Py::Object PythonExtensionBase::sequence_item( Py_ssize_t ) -{ missing_method( sequence_item ); return Py::Nothing(); } - -Py::Object PythonExtensionBase::sequence_slice( Py_ssize_t, Py_ssize_t ) -{ missing_method( sequence_slice ); return Py::Nothing(); } - -int PythonExtensionBase::sequence_ass_item( Py_ssize_t, const Py::Object & ) -{ missing_method( sequence_ass_item ); return -1; } - -int PythonExtensionBase::sequence_ass_slice( Py_ssize_t, Py_ssize_t, 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 -Py_ssize_t PythonExtensionBase::buffer_getreadbuffer( Py_ssize_t, void** ) -{ missing_method( buffer_getreadbuffer ); return -1; } - -Py_ssize_t PythonExtensionBase::buffer_getwritebuffer( Py_ssize_t, void** ) -{ missing_method( buffer_getwritebuffer ); return -1; } - -Py_ssize_t PythonExtensionBase::buffer_getsegcount( Py_ssize_t* ) -{ 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( 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() ); - } - - 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( 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( module_name.c_str() ), NULL, NULL ), true ); -} - -void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::string& name, ExtensionExceptionType &parent) - { - std::string module_name( module.fullName() ); - module_name += '.'; - module_name += name; - - set( PyErr_NewException( const_cast( module_name.c_str() ), parent.ptr(), NULL ), true ); -} - -ExtensionExceptionType::~ExtensionExceptionType() -{ -} - -Exception::Exception( ExtensionExceptionType &exception, const std::string& reason ) -{ - PyErr_SetString (exception.ptr(), reason.c_str()); -} - -Exception::Exception( ExtensionExceptionType &exception, Object &reason ) -{ - PyErr_SetObject (exception.ptr(), reason.ptr()); -} - -Exception::Exception( PyObject* exception, Object &reason ) -{ - PyErr_SetObject (exception, reason.ptr()); -} - -} // end of namespace Py diff --git a/python/pythonconfig.h b/python/pythonconfig.h index 1cd1c1a..a21f49d 100644 --- a/python/pythonconfig.h +++ b/python/pythonconfig.h @@ -1,94 +1,94 @@ /*************************************************************************** * pythonconfig.h * This file is part of the KDE project * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * You should have received a copy of the GNU Library General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. ***************************************************************************/ #ifndef KROSS_PYTHON_CONFIG_H #define KROSS_PYTHON_CONFIG_H // Prevent warnings #if defined(_XOPEN_SOURCE) #undef _XOPEN_SOURCE #endif #if defined(_POSIX_C_SOURCE) #undef _POSIX_C_SOURCE #endif /* Prevent multiple conflicting definitions of swab from stdlib.h and unistd.h See also http://bugs.kde.org/show_bug.cgi?id=156950 */ #if defined(__sun) || defined(sun) #if defined(_XPG4) #undef _XPG4 #endif #endif // The Python.h needs to be included first. #include #include #include #include #include #include // Include the PyCXX stuff. -#include "cxx/Config.hxx" -#include "cxx/Objects.hxx" -#include "cxx/Extensions.hxx" -#include "cxx/Exception.hxx" +#include "CXX/Config.hxx" +#include "CXX/Objects.hxx" +#include "CXX/Extensions.hxx" +#include "CXX/Exception.hxx" // The version of this python plugin. This will be exported // to the scripting code. That way we're able to write // scripting code for different incompatible Kross python // bindings by checking the version. You should increment // this number only if you really know what you're doing. //#define KROSS_PYTHON_VERSION 1 // Enable debugging for Kross::PythonInterpreter //#define KROSS_PYTHON_INTERPRETER_DEBUG // Enable debugging for Kross::PythonScript #define KROSS_PYTHON_SCRIPT_CTOR_DEBUG #define KROSS_PYTHON_SCRIPT_DTOR_DEBUG //#define KROSS_PYTHON_SCRIPT_INIT_DEBUG //#define KROSS_PYTHON_SCRIPT_FINALIZE_DEBUG #define KROSS_PYTHON_SCRIPT_EXEC_DEBUG //#define KROSS_PYTHON_SCRIPT_CALLFUNC_DEBUG #define KROSS_PYTHON_SCRIPT_AUTOCONNECT_DEBUG // Enable debugging for Kross::PythonModule //#define KROSS_PYTHON_MODULE_CTORDTOR_DEBUG //#define KROSS_PYTHON_MODULE_IMPORT_DEBUG // Enable debugging for Kross::PythonExtension //#define KROSS_PYTHON_EXTENSION_CTORDTOR_DEBUG //#define KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG //#define KROSS_PYTHON_EXTENSION_GETATTR_DEBUG //#define KROSS_PYTHON_EXTENSION_SETATTR_DEBUG //#define KROSS_PYTHON_EXTENSION_CALL_DEBUG //#define KROSS_PYTHON_EXTENSION_CONNECT_DEBUG //#define KROSS_PYTHON_EXTENSION_NUMERIC_DEBUG // Enable debugging for Kross::Function //#define KROSS_PYTHON_FUNCTION_DEBUG // Enable debugging for Kross::PythonType and Kross::PythonMetaTypeFactory //#define KROSS_PYTHON_VARIANT_DEBUG #define KROSS_PYTHON_EXCEPTION_DEBUG #endif diff --git a/python/pythonextension.cpp b/python/pythonextension.cpp index 793d0a3..a10444a 100644 --- a/python/pythonextension.cpp +++ b/python/pythonextension.cpp @@ -1,781 +1,781 @@ /*************************************************************************** * pythonextension.cpp * This file is part of the KDE project * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * You should have received a copy of the GNU Library General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. ***************************************************************************/ #include "pythonextension.h" #include "pythoninterpreter.h" #include "pythonvariant.h" #include "pythonfunction.h" #include #include #include namespace Kross { /// \internal d-pointer class. class PythonExtension::Private { public: /// The QObject this PythonExtension wraps. QPointer object; /// Defines if this PythonExtension the owner of the QObject. bool owner; #ifdef KROSS_PYTHON_EXTENSION_CTORDTOR_DEBUG /// \internal string for debugging. QString debuginfo; #endif /// The cached list of methods. QHash methods; /// The cached list of properties. QHash properties; /// The cached list of enumerations. QHash enumerations; /// The \a PythonFunction instances. QHash functions; /// The cached list of methodnames. Py::List methodnames; /// The cached list of membernames. Py::List membernames; /// The proxymethod which will handle all calls to our \a PythonExtension instance. Py::MethodDefExt* proxymethod; }; } using namespace Kross; void PythonExtension::init_type() { behaviors().name("KrossPythonExtension"); behaviors().doc("The KrossPythonExtension object wraps a QObject into the world of python."); //behaviors().supportPrint(); behaviors().supportGetattr(); behaviors().supportSetattr(); //behaviors().supportGetattro(); //behaviors().supportSetattro(); behaviors().supportCompare(); //behaviors().supportRepr(); //behaviors().supportStr(); behaviors().supportHash(); //behaviors().supportIter(); //behaviors().supportCall(); behaviors().supportSequenceType(); behaviors().supportMappingType(); behaviors().supportNumberType(); //behaviors().supportBufferType(); add_varargs_method("className", &PythonExtension::getClassName, "Return the name of the QObject class."); //add_varargs_method("classInfo", &PythonExtension::getClassInfo, "Return a list of key,value-tuples of class information."); add_varargs_method("signalNames", &PythonExtension::getSignalNames, "Return list of signal names the QObject provides."); add_varargs_method("slotNames", &PythonExtension::getSlotNames, "Return list of slot names the QObject provides."); add_varargs_method("propertyNames", &PythonExtension::getPropertyNames, "Return list of property names the QObject provides."); //add_varargs_method("dynamicPropertyNames", &PythonExtension::getDynamicPropertyNames, ""); add_varargs_method("property", &PythonExtension::getProperty, "Return a property value."); add_varargs_method("setProperty", &PythonExtension::setProperty, "Set a property value."); add_varargs_method("__toPointer__", &PythonExtension::toPointer, "Return the void* pointer of the QObject."); //add_varargs_method("__fromPointer__", &PythonExtension::fromPointer, "Set the QObject* to the passed void* pointer."); add_varargs_method("connect", &PythonExtension::doConnect, "Connect signal, slots or python functions together."); add_varargs_method("disconnect", &PythonExtension::doDisconnect, "Disconnect signal, slots or python functions that are connected together."); } PythonExtension::PythonExtension(QObject* object, bool owner) : Py::PythonExtension() , d( new Private() ) { d->object = object; d->owner = owner; #ifdef KROSS_PYTHON_EXTENSION_CTORDTOR_DEBUG d->debuginfo = object ? QString("%1 (%2)").arg(object->objectName()).arg(object->metaObject()->className()) : "NULL"; krossdebug( QString("PythonExtension::Constructor object=%1").arg(d->debuginfo) ); #endif d->proxymethod = new Py::MethodDefExt( "", // methodname, not needed cause we use the method only internaly. - 0, // method that should handle the callback, not needed cause proxyhandler will handle it. + Py::MethodDefExt::method_varargs_function_t( 0 ), // method that should handle the callback, not needed cause proxyhandler will handle it. Py::method_varargs_call_handler_t( proxyhandler ), // callback handler "" // documentation ); if(d->object) { const QMetaObject* metaobject = d->object->metaObject(); { // initialize methods. const int count = metaobject->methodCount(); for(int i = 0; i < count; ++i) { QMetaMethod member = metaobject->method(i); const QByteArray name = member.name(); if(! d->methods.contains(name)) { d->methods.insert(name, Py::Int(i)); d->methodnames.append(Py::String(name)); } } } { // initialize properties const int count = metaobject->propertyCount(); for(int i = 0; i < count; ++i) { QMetaProperty prop = metaobject->property(i); d->properties.insert(prop.name(), prop); d->membernames.append( Py::String(prop.name()) ); } } { // initialize enumerations const int count = metaobject->enumeratorCount(); for(int i = 0; i < count; ++i) { QMetaEnum e = metaobject->enumerator(i); const int kc = e.keyCount(); for(int k = 0; k < kc; ++k) { const QByteArray name = /*e.name() +*/ e.key(k); d->enumerations.insert(name, e.value(k)); d->membernames.append( Py::String(name) ); } } } } } PythonExtension::~PythonExtension() { #ifdef KROSS_PYTHON_EXTENSION_CTORDTOR_DEBUG krossdebug( QString("PythonExtension::Destructor object=%1").arg(d->debuginfo) ); #endif if( d->owner ) delete d->object; qDeleteAll(d->functions);//FIXME curently it may delete connections (i.e. PythonFunctions) that we want to stay! delete d->proxymethod; delete d; } QObject* PythonExtension::object() const { return d->object; } Py::Object PythonExtension::getattr(const char* n) { #ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG krossdebug( QString("PythonExtension::getattr name='%1'").arg(n) ); #endif // handle internal methods if(n[0] == '_') { if(strcmp(n,"__methods__") == 0) return d->methodnames; if(strcmp(n,"__members__") == 0) return d->membernames; //if(strcmp(n,"__dict__") == 0) // return PythonType::toPyObject( QStringList() ); if(strcmp(n,"__all__") == 0) //this hack is needed to prevent "from-import-* object has no __dict__ and no __all__" exceptions return d->methodnames; } // look if the attribute is a method if(d->methods.contains(n)) { #ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG krossdebug( QString("PythonExtension::getattr name='%1' is a method.").arg(n) ); #endif // Python is more dynamic then someone thinks of what provides us bigger problems // here since we are not able to cache the whole lookup and need to create and return // a new function object at each request since 1) they may used internaly by python // to redirect this method/attr to somebody else and 2) those returned function object // may prevent this object instance from beeing removed by the garbage collector. //FIXME use callcache here to improve the performance by some factors! Py::Tuple t(3); t[0] = Py::Object(this); // reference to this instance, set at getattr() t[1] = d->methods[n]; // the first index used for faster access t[2] = Py::String(n); // the name of the method t.increment_reference_count(); // the PyCFunction_New shoukd take care of removing our ref... return Py::Object(PyCFunction_New( &d->proxymethod->ext_meth_def, t.ptr() ), true); } // look if the attribute is a property if(d->properties.contains(n) && d->object) { QMetaProperty property = d->properties[n]; #ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG krossdebug( QString("PythonExtension::getattr name='%1' is a property: type=%2 valid=%3 readable=%4 scriptable=%5 writable=%6 user=%7 usertype=%8") .arg(n).arg(property.typeName()).arg(property.isValid()) .arg(property.isReadable()).arg(property.isScriptable(d->object)).arg(property.isWritable()) .arg(property.isUser(d->object)).arg(property.userType()) ); #endif if(! property.isReadable()) { Py::AttributeError( ::QString("Attribute \"%1\" is not readable.").arg(n).toLatin1().constData() ); return Py::None(); } return PythonType::toPyObject( property.read(d->object) ); } // look if the attribute is an enumerator if(d->enumerations.contains(n)) { return Py::Int(d->enumerations[n]); } // look if it's a dynamic property if(d->object && d->object->dynamicPropertyNames().contains(n)) { return PythonType::toPyObject( d->object->property(n) ); } // finally redirect the unhandled attribute-request... //return Py::PythonExtension::getattr_methods(n); return Py::PythonExtension::getattr(n); } int PythonExtension::setattr(const char* n, const Py::Object& value) { // look if the attribute is a property if(d->properties.contains(n) && d->object) { QMetaProperty property = d->properties[n]; #ifdef KROSS_PYTHON_EXTENSION_SETATTR_DEBUG krossdebug( QString("PythonExtension::setattr name='%1' is a property: type=%2 valid=%3 readable=%4 scriptable=%5 writable=%6 usertype=%7") .arg(n).arg(property.typeName()).arg(property.isValid()) .arg(property.isReadable()).arg(property.isScriptable(d->object)).arg(property.isWritable()) .arg(property.isUser(d->object)).arg(property.userType()) ); #endif if(! property.isWritable()) { Py::AttributeError( ::QString("Attribute \"%1\" is not writable.").arg(n).toLatin1().constData() ); return -1; // indicate error } QVariant v = PythonType::toVariant(value); if(! property.write(d->object, v)) { Py::AttributeError( ::QString("Setting attribute \"%1\" failed.").arg(n).toLatin1().constData() ); return -1; // indicate error } #ifdef KROSS_PYTHON_EXTENSION_SETATTR_DEBUG krossdebug( QString("PythonExtension::setattr name='%1' value='%2'").arg(n).arg(v.toString()) ); #endif return 0; // indicate success } // finally redirect the unhandled attribute-request... return Py::PythonExtension::setattr(n, value); } int PythonExtension::compare(const Py::Object& other) { if(Py::PythonExtension::check( other )) { Py::ExtensionObject extobj( other ); PythonExtension* extension = extobj.extensionObject(); QObject* obj = extension->object(); //krossdebug( QString("PythonExtension::compare this.name='%1' other.name='%2' other.pyobject='%3'").arg(d->object ? d->object->objectName() : "NULL").arg(obj ? obj->objectName() : "NULL").arg(other.as_string().c_str()) ); //Q_ASSERT( obj ); //Q_ASSERT( object() ); return obj == object() ? 0 : ( obj > object() ? -1 : 1 ); } PyErr_SetObject(PyExc_TypeError, other.ptr()); return -1; } long PythonExtension::hash() { return long( (QObject*) d->object ); } /* objectName is a property anyway and therefore already accessible Py::Object PythonExtension::getObjectName(const Py::Tuple&) { return PythonType::toPyObject( d->object->objectName() ); } */ Py::Object PythonExtension::getClassName(const Py::Tuple&) { return PythonType::toPyObject( d->object->metaObject()->className() ); } Py::Object PythonExtension::getSignalNames(const Py::Tuple&) { Py::List list; const QMetaObject* metaobject = d->object->metaObject(); const int count = metaobject->methodCount(); for(int i = 0; i < count; ++i) { QMetaMethod m = metaobject->method(i); QByteArray signature = m.methodSignature(); if( m.methodType() == QMetaMethod::Signal) list.append( Py::String(signature.constData()) ); } return list; } Py::Object PythonExtension::getSlotNames(const Py::Tuple&) { Py::List list; const QMetaObject* metaobject = d->object->metaObject(); const int count = metaobject->methodCount(); for(int i = 0; i < count; ++i) { QMetaMethod m = metaobject->method(i); QByteArray signature = m.methodSignature(); if( m.methodType() == QMetaMethod::Slot) list.append( Py::String(signature.constData()) ); } return list; } Py::Object PythonExtension::getPropertyNames(const Py::Tuple&) { Py::List list; const QMetaObject* metaobject = d->object->metaObject(); const int count = metaobject->propertyCount(); for(int i = 0; i < count; ++i) list.append( Py::String(metaobject->property(i).name()) ); return list; } Py::Object PythonExtension::getProperty(const Py::Tuple& args) { if( args.size() != 1 ) { Py::TypeError("Expected the propertyname as argument."); return Py::None(); } return PythonType::toPyObject( d->object->property( PythonType::toVariant(args[0]).constData() ) ); } Py::Object PythonExtension::setProperty(const Py::Tuple& args) { if( args.size() != 2 ) { Py::TypeError("Expected the propertyname and the value as arguments."); return Py::None(); } return PythonType::toPyObject( d->object->setProperty( PythonType::toVariant(args[0]).constData(), PythonType::toVariant(args[1]) ) ); } Py::Object PythonExtension::toPointer(const Py::Tuple&) { QObject* obj = d->object; PyObject* qobjectptr = PyLong_FromVoidPtr( (void*) obj ); //PyObject* o = Py_BuildValue ("N", mw); return Py::asObject( qobjectptr ); //PythonPyQtExtension* pyqtextension = new PythonPyQtExtension(self, args); //return pyqtextension; } /* Py::Object PythonExtension::fromPointer(fromPointer(const Py::Tuple&) { QObject* object = dynamic_cast< QObject* >(PyLong_AsVoidPtr( args[0] )); } */ Py::Object PythonExtension::doConnect(const Py::Tuple& args) { #ifdef KROSS_PYTHON_EXTENSION_CONNECT_DEBUG krossdebug( QString("PythonExtension::doConnect" ) ); for(uint i = 0; i < args.size(); ++i) try { QVariant v = PythonType::toVariant( args[i] ); krossdebug( QString(" Argument index=%1 variant.toString=%2 variant.typeName=%3").arg(i).arg(v.toString()).arg(v.typeName()) ); } catch(Py::Exception& e) { // may happen e.g. on "function" types PyTypeObject *type = (PyTypeObject*) args[i].type().ptr(); krossdebug( QString(" Argument index=%1 tp_name=%2").arg(i).arg(type->tp_name) ); e.clear(); } #endif if( args.size() < 2 ) { Py::TypeError("Expected at least 2 arguments."); return PythonType::toPyObject(false); } uint idx; // next argument to check QObject* sender; // the sender object QByteArray sendersignal; // the sender signal if( args[0].isString() ) { // connect(signal, ...) //krossdebug( QString("PythonExtension::doConnect connect(signal, ...)" ) ); sender = d->object; sendersignal = PythonType::toVariant( args[0] ); idx = 1; } else { // connect(sender, signal, ...) //krossdebug( QString("PythonExtension::doConnect connect(sender, signal, ...)" ) ); Py::ExtensionObject extobj(args[0]); PythonExtension* extension = extobj.extensionObject(); if(! extension) { Py::TypeError( ::QString("First argument needs to be a signalname or a sender-object.").toLatin1().constData() ); return PythonType::toPyObject(false); } sender = extension->object(); if( ! args[1].isString() ) { Py::TypeError( ::QString("Second argument needs to be a signalname.").toLatin1().constData() ); return PythonType::toPyObject(false); } sendersignal = PythonType::toVariant( args[1] ); idx = 2; if( args.size() <= idx ) { Py::TypeError( ::QString("Expected at least %1 arguments.").arg(idx+1).toLatin1().constData() ); return PythonType::toPyObject(false); } } QObject* receiver; // the receiver object QByteArray receiverslot; // the receiver slot if( args[idx].isCallable() ) { // connect with python function //krossdebug( QString("PythonExtension::doConnect connect with python function" ) ); Py::Callable func(args[idx]); // the callable python function PythonFunction* function = new PythonFunction(sender, sendersignal, func); d->functions.insertMulti(sendersignal, function); receiver = function; receiverslot = sendersignal; } else { // connect with receiver and slot //krossdebug( QString("PythonExtension::doConnect connect with receiver and slot" ) ); if( args[idx].isString() ) { // connect(..., slot) receiver = d->object; receiverslot = PythonType::toVariant( args[idx] ); } else { // connect(..., receiver, slot) Py::ExtensionObject extobj(args[idx]); PythonExtension* extension = extobj.extensionObject(); if(! extension) { Py::TypeError( ::QString("Receiver argument needs to be a slotname or a receiver-object.").toLatin1().constData() ); return PythonType::toPyObject(false); } receiver = extension->object(); idx++; if( args.size() < idx ) { Py::TypeError( ::QString("Expected at least %1 arguments.").arg(idx+1).toLatin1().constData() ); return PythonType::toPyObject(false); } if( ! args[idx].isString() ) { Py::TypeError( ::QString("Expected receiver slotname as argument %1.").arg(idx+1).toLatin1().constData() ); return PythonType::toPyObject(false); } receiverslot = PythonType::toVariant( args[idx] ); } } // Dirty hack to replace SIGNAL() and SLOT() macros. If the user doesn't // defined them explicit, we assume it's wanted to connect from a signal to // a slot. This seems to be the most flexible solution so far... if( ! sendersignal.startsWith('1') && ! sendersignal.startsWith('2') ) sendersignal.prepend('2'); // prepending 2 means SIGNAL(...) if( ! receiverslot.startsWith('1') && ! receiverslot.startsWith('2') ) receiverslot.prepend('1'); // prepending 1 means SLOT(...) #ifdef KROSS_PYTHON_EXTENSION_CONNECT_DEBUG krossdebug( QString("PythonExtension::doConnect sender=%1 signal=%2 receiver=%3 slot=%4").arg(sender->objectName()).arg(sendersignal.constData()).arg(receiver->objectName()).arg(receiverslot.constData()).toLatin1().constData() ); #endif if(! QObject::connect(sender, sendersignal, receiver, receiverslot) ) { krosswarning( QString("PythonExtension::doConnect Failed to connect").toLatin1().constData() ); return PythonType::toPyObject(false); } return PythonType::toPyObject(true); } Py::Object PythonExtension::doDisconnect(const Py::Tuple&) { //TODO return PythonType::toPyObject(false); } PyObject* PythonExtension::proxyhandler(PyObject *_self_and_name_tuple, PyObject *args) { /* class GilState { public: GilState() { m_gilstate = PyGILState_Ensure(); } // Acquire interpreter lock ~GilState() { PyGILState_Release( m_gilstate ); } // Free interpreter lock private: PyGILState_STATE m_gilstate; }; GilState gil; */ try { Py::Tuple selftuple(_self_and_name_tuple); int methodindex = Py::Int(selftuple[1]); QByteArray ba = Py::String(selftuple[2]).as_string().c_str(); const char* methodname = ba.constData(); #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG krossdebug( QString("PythonExtension::proxyhandler methodname=%1 methodindex=%2").arg(methodname).arg(methodindex) ); #endif PythonExtension *self = static_cast( selftuple[0].ptr() ); if( ! self->d->object ) { Py::RuntimeError( QString("Underlying QObject instance of method '%1' was removed.").arg(methodname).toLatin1().constData() ); return Py_None; } Py::Tuple argstuple(args); const int argssize = int( argstuple.size() ); QMetaMethod metamethod = self->d->object->metaObject()->method( methodindex ); if(metamethod.parameterTypes().size() != argssize) { bool found = false; const int count = self->d->object->metaObject()->methodCount(); for(++methodindex; methodindex < count; ++methodindex) { metamethod = self->d->object->metaObject()->method( methodindex ); const QByteArray name = metamethod.name(); if(name == methodname) { if(metamethod.parameterTypes().size() == argssize) { found = true; break; } } } if(! found) { krosswarning( QString("PythonExtension::proxyhandler The method '%1' does not expect %2 arguments.").arg(methodname).arg(argssize) ); throw Py::TypeError( QString("Invalid number of arguments for the method %1").arg(methodname).toLatin1().constData() ); } } #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG krossdebug( QString("PythonExtension::proxyhandler QMetaMethod idx=%1 sig=%2 tag=%3 type=%4").arg(methodindex).arg(metamethod.signature()).arg(metamethod.tag()).arg(metamethod.typeName()) ); for(int i = 0; i < argssize; ++i) { QVariant v; try { v = PythonType::toVariant( argstuple[i] ); } catch(Py::Exception& e) { v = Py::value(e).as_string().c_str(); e.clear(); } krossdebug( QString(" Argument index=%1 variant.toString=%2 variant.typeName=%3").arg(i).arg(v.toString()).arg(v.typeName()) ); } #endif Py::Object pyresult; { QList typelist = metamethod.parameterTypes(); const int typelistcount = typelist.count(); bool hasreturnvalue = strcmp(metamethod.typeName(),"") != 0; // exact 1 returnvalue + 0..9 arguments Q_ASSERT(typelistcount <= 9); QVarLengthArray variantargs(typelistcount + 1); QVarLengthArray voidstarargs(typelistcount + 1); // set the return value if(hasreturnvalue) { MetaType* returntype = PythonMetaTypeFactory::create( metamethod.typeName(), Py::Object(), false /*owner*/ ); variantargs[0] = returntype; voidstarargs[0] = returntype->toVoidStar(); #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG krossdebug( QString("PythonExtension::proxyhandler typeName=%1").arg(metamethod.typeName()) ); #endif } else { variantargs[0] = 0; voidstarargs[0] = (void*)0; } // set the arguments int idx = 1; try { for(; idx <= typelistcount; ++idx) { variantargs[idx] = PythonMetaTypeFactory::create( typelist[idx-1].constData(), argstuple[idx - 1], false /*owner*/ ); voidstarargs[idx] = variantargs[idx]->toVoidStar(); } } catch(Py::Exception& e) { // Seems PythonMetaTypeFactory::create raised an exception // up. Clean all already allocated MetaType instances. for(int i = 0; i < idx; ++i) delete variantargs[i]; throw e; // re-throw exception } // call the method now int r = self->d->object->qt_metacall(QMetaObject::InvokeMetaMethod, methodindex, &voidstarargs[0]); #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG krossdebug( QString("RESULT nr=%1").arg(r) ); #else Q_UNUSED(r); #endif // eval the return-value if(hasreturnvalue) { QVariant v; if( Kross::MetaTypeHandler* handler = Kross::Manager::self().metaTypeHandler(metamethod.typeName()) ) { #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG krossdebug( QString("Returnvalue of type '%2' has a handler").arg(metamethod.typeName()) ); #endif void *ptr = (*reinterpret_cast( variantargs[0]->toVoidStar() )); v = handler->callHandler(ptr); } else { v = QVariant(variantargs[0]->typeId(), variantargs[0]->toVoidStar()); if( ! Kross::Manager::self().strictTypesEnabled() ) { if( v.type() == QVariant::Invalid && QByteArray(metamethod.typeName()).endsWith("*") ) { #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG krossdebug( QString("Returnvalue of type '%2' will be reinterpret_cast").arg(metamethod.typeName()) ); #endif QObject* obj = (*reinterpret_cast( variantargs[0]->toVoidStar() )); v.setValue( (QObject*) obj ); } } } pyresult = PythonType::toPyObject(v); #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG krossdebug( QString("Returnvalue typeId=%1 metamethod.typename=%2 variant.toString=%3 variant.typeName=%4 pyobject=%5").arg(variantargs[0]->typeId()).arg(metamethod.typeName()).arg(v.toString()).arg(v.typeName()).arg(pyresult.as_string().c_str()) ); #endif } // finally free the PythonVariable instances for(int i = 0; i <= typelistcount; ++i) delete variantargs[i]; } pyresult.increment_reference_count(); // don't destroy PyObject* if pyresult got destroyed. return pyresult.ptr(); } catch(Py::Exception& e) { QStringList trace; int lineno; PythonInterpreter::extractException(trace, lineno); krosswarning( QString("PythonExtension::proxyhandler Had exception on line %1:\n%2 \n%3").arg(lineno).arg(Py::value(e).as_string().c_str()).arg(trace.join("\n")) ); PyErr_Print(); //e.clear(); } return Py_None; } -int PythonExtension::sequence_length() +PyCxx_ssize_t PythonExtension::sequence_length() { return d->object->children().count(); } Py::Object PythonExtension::sequence_concat(const Py::Object& obj) { throw Py::RuntimeError( QString("Unsupported: PythonExtension::sequence_concat %1").arg(obj.as_string().c_str()).toLatin1().constData() ); } Py::Object PythonExtension::sequence_repeat(Py_ssize_t index) { // what we do here is rather evil and does not make sense at all. We assume that something // like "myobjinstance * 2" means, that the pointer-address should be multiplied by 2. This // is the case to keep backward-compatibility with SuperKaramba. In normal cases you wan't // use such kind of logic within your python scripts anyway + we can't guarantee that the // resulting number may not overflow or something like this. return Py::Long( long( (QObject*) d->object ) * index ); } Py::Object PythonExtension::sequence_item(Py_ssize_t index) { if(index < d->object->children().count()) return Py::asObject(new PythonExtension( d->object->children().at(index) )); return Py::asObject( Py::new_reference_to( NULL ) ); } Py::Object PythonExtension::sequence_slice(Py_ssize_t from, Py_ssize_t to) { Py::List list; if(from >= 0) { const int count = d->object->children().count(); for(int i = from; i <= to && i < count; ++i) list.append( Py::asObject(new PythonExtension( d->object->children().at(i) )) ); } return list; } int PythonExtension::sequence_ass_item(Py_ssize_t index, const Py::Object& obj) { throw Py::RuntimeError( QString("Unsupported: PythonExtension::sequence_ass_item %1 %2").arg(index).arg(obj.as_string().c_str()).toLatin1().constData() ); } int PythonExtension::sequence_ass_slice(Py_ssize_t from, Py_ssize_t to, const Py::Object& obj) { throw Py::RuntimeError( QString("Unsupported: PythonExtension::sequence_ass_slice %1 %2 %3").arg(from).arg(to).arg(obj.as_string().c_str()).toLatin1().constData() ); } -int PythonExtension::mapping_length() +PyCxx_ssize_t PythonExtension::mapping_length() { return d->object->children().count(); } Py::Object PythonExtension::mapping_subscript(const Py::Object& obj) { QString name = Py::String(obj).as_string().c_str(); QObject* object = d->object->findChild< QObject* >( name ); if(! object) { foreach(QObject* o, d->object->children()) { if(name == o->metaObject()->className()) { object = o; break; } } } if(object) return Py::asObject(new PythonExtension(object)); return Py::asObject( Py::new_reference_to( NULL ) ); } int PythonExtension::mapping_ass_subscript(const Py::Object& obj1, const Py::Object& obj2) { throw Py::RuntimeError( QString("Unsupported: PythonExtension::mapping_ass_subscript %1 %2").arg(obj1.as_string().c_str()).arg(obj2.as_string().c_str()).toLatin1().constData() ); } int PythonExtension::number_nonzero() { #ifdef KROSS_PYTHON_EXTENSION_NUMERIC_DEBUG krossdebug("PythonExtension::number_nonzero"); #endif return d->object ? 1 : 0; } Py::Object PythonExtension::number_int() { #ifdef KROSS_PYTHON_EXTENSION_NUMERIC_DEBUG krossdebug("PythonExtension::number_int"); #endif return Py::Int( hash() ); } Py::Object PythonExtension::number_long() { #ifdef KROSS_PYTHON_EXTENSION_NUMERIC_DEBUG krossdebug("PythonExtension::number_long"); #endif return Py::Long( hash() ); } Py::Object PythonExtension::number_hex() { #ifdef KROSS_PYTHON_EXTENSION_NUMERIC_DEBUG krossdebug("PythonExtension::number_hex"); #endif void* ptr = (QObject*) d->object; return Py::Object(PyString_FromFormat("%p",ptr),true); } diff --git a/python/pythonextension.h b/python/pythonextension.h index 75724d9..b4396da 100644 --- a/python/pythonextension.h +++ b/python/pythonextension.h @@ -1,191 +1,191 @@ /*************************************************************************** * pythonextension.h * This file is part of the KDE project * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * You should have received a copy of the GNU Library General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. ***************************************************************************/ #ifndef KROSS_PYTHONEXTENSION_H #define KROSS_PYTHONEXTENSION_H #include "pythonconfig.h" #include #include #include #include #include #include namespace Kross { // Forward declaration. class PythonExtension; class PythonScript; /** * The PythonExtension class implements a Py::Object to wrap a * QObject instance into the world of Python. */ class PythonExtension : public Py::PythonExtension { friend class PythonScript; public: /** * Initialize the class details (methods, etc). * To be called only once. */ static void init_type(); /** * Constructor. * * \param object The QObject this extension instance wraps. * \param owner Defines if this PythonExtension the owner * of the QObject \p object . If that's the case the QObject * will be destroyed if this PythonExtension is destroyed. */ explicit PythonExtension(QObject* object, bool owner = false); /** * Destructor. */ virtual ~PythonExtension(); /** * \return the QObject instance this extension instance wraps. */ QObject* object() const; /** * Handle getting of attributes. An attribute could be a property * as well as a pointer to a callable memberfunction. * * \param name The name of the attribute that should be handled. * \return An \a Py::Object that could be a value or a callable * object. Python will decide what to do with the returnvalue. */ virtual Py::Object getattr(const char* name); //virtual Py::Object getattr_methods(const char* name); /** * Handle setting of attributes. * * \param name The name of the attribute. * \param value The value to set the attribute. * \return -1 on failure and 0 on success. */ virtual int setattr(const char* name, const Py::Object& value); /** * Compare two objects. * * \param other The object this object should be compared with. * \return 0 if the equal, 1 if self is bigger than other and -1 * if self is smaller than other. */ virtual int compare(const Py::Object& other); virtual long hash(); // Sequence - virtual int sequence_length(); + virtual PyCxx_ssize_t sequence_length(); virtual Py::Object sequence_concat(const Py::Object&); virtual Py::Object sequence_repeat(Py_ssize_t); virtual Py::Object sequence_item(Py_ssize_t); virtual Py::Object sequence_slice(Py_ssize_t, Py_ssize_t); virtual int sequence_ass_item(Py_ssize_t, const Py::Object&); virtual int sequence_ass_slice(Py_ssize_t, Py_ssize_t, const Py::Object&); // Mapping - virtual int mapping_length(); + virtual PyCxx_ssize_t mapping_length(); virtual Py::Object mapping_subscript(const Py::Object&); virtual int mapping_ass_subscript(const Py::Object&, const Py::Object&); // Number virtual int number_nonzero(); //virtual Py::Object number_negative(); //virtual Py::Object number_positive(); //virtual Py::Object number_absolute(); //virtual Py::Object number_invert(); virtual Py::Object number_int(); //virtual Py::Object number_float(); virtual Py::Object number_long(); //virtual Py::Object number_oct(); virtual Py::Object number_hex(); //virtual Py::Object number_add( const Py::Object & ); //virtual Py::Object number_subtract( const Py::Object & ); //virtual Py::Object number_multiply( const Py::Object & ); //virtual Py::Object number_divide( const Py::Object & ); //virtual Py::Object number_remainder( const Py::Object & ); //virtual Py::Object number_divmod( const Py::Object & ); //virtual Py::Object number_lshift( const Py::Object & ); //virtual Py::Object number_rshift( const Py::Object & ); //virtual Py::Object number_and( const Py::Object & ); //virtual Py::Object number_xor( const Py::Object & ); //virtual Py::Object number_or( const Py::Object & ); //virtual Py::Object number_power( const Py::Object &, const Py::Object & ); // Buffer //virtual Py_ssize_t buffer_getreadbuffer( Py_ssize_t, void** ); //virtual Py_ssize_t buffer_getwritebuffer( Py_ssize_t, void** ); //virtual Py_ssize_t buffer_getsegcount( Py_ssize_t* ); private: /// \internal d-pointer class. class Private; /// \internal d-pointer instance. Private* const d; /// Return the name of the QObject class. Py::Object getClassName(const Py::Tuple&); /// Return list of signal names the QObject provides. Py::Object getSignalNames(const Py::Tuple&); /// Return list of slot names the QObject provides. Py::Object getSlotNames(const Py::Tuple&); /// Return list of property names the QObject provides. Py::Object getPropertyNames(const Py::Tuple&); /// Return a property value. Py::Object getProperty(const Py::Tuple&); /// Set a property value. Py::Object setProperty(const Py::Tuple&); Py::Object toPointer(const Py::Tuple&); //Py::Object fromPointer(const Py::Tuple&); /// Connect signal, slots or python functions together. Py::Object doConnect(const Py::Tuple&); /// Disconnect signal, slots or python functions that are connected together. Py::Object doDisconnect(const Py::Tuple&); /** * The static proxy-handler which will be used to dispatch * a call to our \a PythonExtension instance and redirect * the call to the matching method. * * \param _self_and_name_tuple A tuple containing as first * argument a reference to our \a PythonExtension * instance. * \param _args The optional passed arguments for the method * which should be called. * \return The returnvalue of the methodcall. */ static PyObject* proxyhandler(PyObject* _self_and_name_tuple, PyObject* _args); }; } #endif