//----------------------------------------------------------------------------- // // 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 "CXX/WrapPython.h" #include "CXX/Version.hxx" #include "CXX/Python3/Config.hxx" #include "CXX/Python3/CxxDebug.hxx" #include "CXX/Python3/Exception.hxx" #include #include STR_STREAM #include #include #include #include #include #include namespace Py { PYCXX_EXPORT void ifPyErrorThrowCxxException(); typedef Py_ssize_t sequence_index_type; // type of an index into a sequence PYCXX_EXPORT Py_ssize_t numeric_limits_max(); // Forward declarations class Object; class Type; template class SeqBase; class Bytes; class String; class List; template class MapBase; class Tuple; class Dict; //===========================================================================// // 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(); } MyType( const Object &other ): Object( other.ptr() ) { validate(); } */ // Alernate version for the constructor to allow for construction from owned pointers: /* explicit MyType( PyObject *pyob ): Object( pyob ) { validate(); } */ // You may wish to add other constructors; see the classes below for examples. // Each constructor must use "set" to set the pointer // and end by validating the pointer you have created. //( 4 ) Each class needs at least these two assignment operators: /* MyType &operator=( const Object &rhs ) { return *this = *rhs; } Mytype &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) 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 PYCXX_EXPORT 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 = NULL; } 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 ) { if( !owned ) { Py::_XINCREF( p ); } validate(); } // Copy constructor acquires new ownership of pointer Object( const Object &ob ) : p( ob.p ) { Py::_XINCREF( p ); validate(); } // Assignment acquires new ownership of pointer Object &operator=( const Object &rhs ) { set( rhs.p ); return *this; } Object &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Destructor virtual ~Object() { release(); } // Loaning the pointer to others, retain ownership PyObject *operator*() const { return p; } // Explicit reference_counting changes void increment_reference_count() { Py::_XINCREF( p ); } void decrement_reference_count() { // not allowed to commit suicide, however if( reference_count() == 1 ) { throw RuntimeError( "Object::decrement_reference_count error." ); } Py::_XDECREF( p ); } // Would like to call this pointer() but messes up STL in SeqBase PyObject *ptr() const { return p; } // // Queries // // Can pyob be used in this object's constructor? virtual bool accepts( PyObject * ) const { // 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 ); } Py_hash_t hashValue() const { return PyObject_Hash( p ); } // 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 == _None(); } bool isCallable() const { return PyCallable_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::_Unicode_Check( p ); } bool isBytes() const { return Py::_Bytes_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 ) { ifPyErrorThrowCxxException(); } } void delAttr( const std::string &s ) { if( PyObject_DelAttrString( p, const_cast( s.c_str() ) ) == -1 ) { ifPyErrorThrowCxxException(); } } // PyObject_SetItem is too weird to be using from C++ // so it is intentionally omitted. void delItem( const Object &key ) { if( PyObject_DelItem( p, *key ) == -1 ) { ifPyErrorThrowCxxException(); } } // Equality and comparison use PyObject_Compare }; // End of class Object // Null can be return from when it is require to return NULL to Python from a method class PYCXX_EXPORT Null: public Object { public: Null() : Object( NULL ) { } virtual ~Null() { } virtual bool accepts( PyObject *pyob ) const { return pyob == NULL; } }; //------------------------------------------------------------ PYCXX_EXPORT bool operator==( const Object &o1, const Object &o2 ); PYCXX_EXPORT bool operator!=( const Object &o1, const Object &o2 ); PYCXX_EXPORT bool operator>=( const Object &o1, const Object &o2 ); PYCXX_EXPORT bool operator<=( const Object &o1, const Object &o2 ); PYCXX_EXPORT bool operator<( const Object &o1, const Object &o2 ); PYCXX_EXPORT bool operator>( const Object &o1, const Object &o2 ); //------------------------------------------------------------ // // Convert an owned Python pointer into a PyCXX Object // inline Object asObject( PyObject *p ) { return Object( p, true ); } // new_reference_to also overloaded below on Object inline PyObject *new_reference_to( PyObject *p ) { Py::_XINCREF( p ); return p; } inline PyObject *new_reference_to( const Object &g ) { PyObject *p = g.ptr(); Py::_XINCREF( p ); return p; } // 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 exclude iostreams. #ifndef CXX_NO_IOSTREAMS PYCXX_EXPORT std::ostream &operator<<( std::ostream &os, const Object &ob ); #endif // Class Type class PYCXX_EXPORT 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 ) set( rhsp ); return *this; } virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Type_Check( pyob ); } }; // =============================================== // class boolean class PYCXX_EXPORT 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 acquires new ownership of pointer Boolean &operator=( const Object &rhs ) { return *this = *rhs; } Boolean &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { // accepts any object that can be converted to a boolean return pyob && PyObject_IsTrue( pyob ) != -1; } Boolean &operator=( bool v ) { set( PyBool_FromLong( v ? 1 : 0 ), true ); return *this; } operator bool() const { return as_bool(); } }; // =============================================== // class Long class PYCXX_EXPORT Long: public Object { public: // Constructor explicit Long( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } 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 ) { validate(); } // create from unsigned long explicit Long( unsigned long v ) : Object( PyLong_FromUnsignedLong( v ), true ) { validate(); } // create from int explicit Long( int v ) : Object( PyLong_FromLong( static_cast( v ) ), true ) { validate(); } #ifdef HAVE_LONG_LONG // create from long long explicit Long( PY_LONG_LONG v ) : Object( PyLong_FromLongLong( v ), true ) { validate(); } // create from unsigned long long explicit Long( unsigned PY_LONG_LONG v ) : Object( PyLong_FromUnsignedLongLong( v ), true ) { validate(); } #endif // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Long_Check( pyob ); } // Assignment acquires new ownership of pointer Long &operator=( const Object &rhs ) { return *this = *rhs; } Long &operator=( PyObject *rhsp ) { 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 PYCXX_PYTHON_2TO3 // PyCXX for Python2 had an Int and LongLong classes typedef Long Int; #ifdef HAVE_LONG_LONG typedef Long LongLong; #endif #endif #if 1 //------------------------------------------------------------ // compare operators bool operator!=( const Long &a, const Long &b ); bool operator!=( const Long &a, int b ); bool operator!=( const Long &a, long b ); bool operator!=( int a, const Long &b ); bool operator!=( long a, const Long &b ); //------------------------------ bool operator==( const Long &a, const Long &b ); bool operator==( const Long &a, int b ); bool operator==( const Long &a, long b ); bool operator==( int a, const Long &b ); bool operator==( long a, const Long &b ); //------------------------------ bool operator>( const Long &a, const Long &b ); bool operator>( const Long &a, int b ); bool operator>( const Long &a, long b ); bool operator>( int a, const Long &b ); bool operator>( long a, const Long &b ); //------------------------------ bool operator>=( const Long &a, const Long &b ); bool operator>=( const Long &a, int b ); bool operator>=( const Long &a, long b ); bool operator>=( int a, const Long &b ); bool operator>=( long a, const Long &b ); //------------------------------ bool operator<( const Long &a, const Long &b ); bool operator<( const Long &a, int b ); bool operator<( const Long &a, long b ); bool operator<( int a, const Long &b ); bool operator<( long a, const Long &b ); //------------------------------ bool operator<=( const Long &a, const Long &b ); bool operator<=( int a, const Long &b ); bool operator<=( long a, const Long &b ); bool operator<=( const Long &a, int b ); bool operator<=( const Long &a, long b ); #ifdef HAVE_LONG_LONG //------------------------------ bool operator!=( const Long &a, PY_LONG_LONG b ); bool operator!=( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator==( const Long &a, PY_LONG_LONG b ); bool operator==( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator>( const Long &a, PY_LONG_LONG b ); bool operator>( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator>=( const Long &a, PY_LONG_LONG b ); bool operator>=( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator<( const Long &a, PY_LONG_LONG b ); bool operator<( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator<=( const Long &a, PY_LONG_LONG b ); bool operator<=( PY_LONG_LONG a, const Long &b ); #endif #endif // =============================================== // class Float // class PYCXX_EXPORT 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 ) set( PyNumber_Float( rhsp ), true ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Float_Check( pyob ); } double as_double() const { return PyFloat_AsDouble( ptr() ); } // convert to double operator double() const { return as_double(); } // 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 Long Float &operator=( const Long &iob ) { set( PyFloat_FromDouble( double( iob.as_long() ) ), true ); return *this; } }; //------------------------------------------------------------ // compare operators bool operator!=( const Float &a, const Float &b ); bool operator!=( const Float &a, double b ); bool operator!=( double a, const Float &b ); //------------------------------ bool operator==( const Float &a, const Float &b ); bool operator==( const Float &a, double b ); bool operator==( double a, const Float &b ); //------------------------------ bool operator>( const Float &a, const Float &b ); bool operator>( const Float &a, double b ); bool operator>( double a, const Float &b ); //------------------------------ bool operator>=( const Float &a, const Float &b ); bool operator>=( const Float &a, double b ); bool operator>=( double a, const Float &b ); //------------------------------ bool operator<( const Float &a, const Float &b ); bool operator<( const Float &a, double b ); bool operator<( double a, const Float &b ); //------------------------------ bool operator<=( const Float &a, const Float &b ); bool operator<=( double a, const Float &b ); bool operator<=( const Float &a, double b ); // =============================================== // class Complex class PYCXX_EXPORT 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 ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Complex_Check( pyob ); } #if !defined( Py_LIMITED_API ) // 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; } #endif // Py_LIMITED_API // 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 Long Complex &operator=( const Long &iob ) { set( PyComplex_FromDoubles( double( iob.as_long() ), 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. Similarly 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 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 ) ) {} seqref( const seqref &range ) : s( range.s ) , offset( range.offset ) , the_item( range.the_item ) {} // TMM: added this seqref ctor for use with STL algorithms seqref( Object &obj ) : s( dynamic_cast< SeqBase&>( 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 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 { // Hint: Upstream version returns std::string::npos that is the maximum // value of a size_t. But when assigned to a ssize_t it will become -1. // Now Python provides 'sys.maxsize' that is the maximum value of a ssize_t // and thus this method should return the same value. // This can be done with 'std::numeric_limits::max()' but due // to a name collision with a macro on Windows we cannot directly call it // here. // So, a workaround is to implement the helper function 'numeric_limits_max'. //return std::string::npos; // ? return numeric_limits_max(); } virtual size_type capacity() const { return size(); } virtual void swap( SeqBase &c ) { SeqBase temp = c; c = ptr(); set( temp.ptr() ); } virtual size_type size() const { return PySequence_Length( ptr() ); } explicit SeqBase() :Object( PyTuple_New( 0 ), true ) { validate(); } explicit SeqBase( PyObject *pyob, bool owned=false ) : 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 ) set( rhsp ); return *this; } virtual bool accepts( PyObject *pyob ) const { return pyob && PySequence_Check( pyob ); } size_type length() const { return PySequence_Length( ptr() ); } // Element access const T operator[]( sequence_index_type index ) const { return getItem( index ); } seqref 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 ) { 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 compatibility const T front() const { return getItem( 0 ); } seqref front() { return seqref( *this, 0 ); } const T back() const { return getItem( size()-1 ); } seqref back() { return seqref( *this, size()-1 ); } void verify_length( size_type required_size ) const { if( size() != required_size ) { throw IndexError( "Unexpected SeqBase length." ); } } void verify_length( size_type min_size, size_type max_size ) const { size_type n = size(); if( n < min_size || n > max_size ) { throw IndexError( "Unexpected SeqBase length." ); } } class iterator { public: using iterator_category = std::random_access_iterator_tag; using value_type = seqref; using difference_type = int; using pointer = value_type*; using reference = value_type&; protected: friend class SeqBase; SeqBase *seq; sequence_index_type count; public: ~iterator() {} iterator() : seq( 0 ) , count( 0 ) {} iterator( SeqBase *s, Py_ssize_t where ) : seq( s ) , count( where ) {} iterator( const iterator &other ) : seq( other.seq ) , count( other.count ) {} bool eql( const iterator &other ) const { return seq->ptr() == other.seq->ptr() && count == other.count; } bool neq( const iterator &other ) const { 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 ) { seq = other.seq; count = other.count; } return *this; } iterator operator+( sequence_index_type n ) const { return iterator( seq, count + n ); } iterator operator-( sequence_index_type n ) const { return iterator( seq, count - n ); } iterator &operator+=( sequence_index_type n ) { count = count + n; return *this; } iterator &operator-=( sequence_index_type n ) { count = count - n; return *this; } sequence_index_type operator-( const iterator &other ) const { if( seq->ptr() != other.seq->ptr() ) { throw RuntimeError( "SeqBase::iterator comparison error" ); } return count - other.count; } // prefix ++ iterator &operator++() { count++; return *this; } // postfix ++ iterator operator++( int ) { return iterator( seq, count++ ); } // prefix -- iterator &operator--() { count--; return *this; } // postfix -- iterator operator--( int ) { return iterator( seq, count-- ); } std::string diagnose() const { std::OSTRSTREAM oss; oss << "iterator diagnosis " << seq << ", " << count << std::ends; return std::string( oss.str() ); } }; // end of class SeqBase::iterator iterator begin() { return iterator( this, 0 ); } iterator end() { return iterator( this, length() ); } class const_iterator { public: using iterator_category = std::random_access_iterator_tag; using value_type = const Object; using difference_type = int; using pointer = value_type*; using reference = value_type&; protected: friend class SeqBase; const SeqBase *seq; sequence_index_type count; public: ~const_iterator() {} const_iterator() : seq( 0 ) , count( 0 ) {} const_iterator( const SeqBase *s, sequence_index_type where ) : seq( s ) , count( where ) {} const_iterator( const const_iterator &other ) : seq( other.seq ) , count( other.count ) {} const T operator*() const { return seq->getItem( count ); } const T operator[]( sequence_index_type i ) const { return seq->getItem( count + i ); } const_iterator &operator=( const const_iterator &other ) { if( this != &other ) { seq = other.seq; count = other.count; } return *this; } const_iterator operator+( sequence_index_type n ) const { return const_iterator( seq, count + n ); } bool eql( const const_iterator &other ) const { return seq->ptr() == other.seq->ptr() && count == other.count; } bool neq( const const_iterator &other ) const { 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-( sequence_index_type n ) { return const_iterator( seq, count - n ); } const_iterator &operator+=( sequence_index_type n ) { count = count + n; return *this; } 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; } // postfix ++ const_iterator operator++( int ) { return const_iterator( seq, count++ ); } // prefix -- const_iterator &operator--() { count--; return *this; } // postfix -- const_iterator operator--( int ) { return const_iterator( seq, count-- ); } }; // end of class SeqBase::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 ); PYCXX_EXPORT extern bool operator==( const Sequence::iterator &left, const Sequence::iterator &right ); PYCXX_EXPORT extern bool operator!=( const Sequence::iterator &left, const Sequence::iterator &right ); PYCXX_EXPORT extern bool operator< ( const Sequence::iterator &left, const Sequence::iterator &right ); PYCXX_EXPORT extern bool operator> ( const Sequence::iterator &left, const Sequence::iterator &right ); PYCXX_EXPORT extern bool operator<=( const Sequence::iterator &left, const Sequence::iterator &right ); PYCXX_EXPORT extern bool operator>=( const Sequence::iterator &left, const Sequence::iterator &right ); PYCXX_EXPORT extern bool operator==( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); PYCXX_EXPORT extern bool operator!=( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); PYCXX_EXPORT extern bool operator< ( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); PYCXX_EXPORT extern bool operator> ( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); PYCXX_EXPORT extern bool operator<=( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); PYCXX_EXPORT 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 // #if !defined(Py_LIMITED_API) && !defined(Py_UNICODE_DEPRECATED) typedef std::basic_string unicodestring; extern Py_UNICODE unicode_null_string[1]; #endif typedef std::basic_string ucs4string; extern char32_t ucs4_null_string[1]; class PYCXX_EXPORT Byte: public Object { public: // Membership virtual bool accepts( PyObject *pyob ) const { return pyob != NULL && Py::_Bytes_Check( pyob ) && PySequence_Length( pyob ) == 1; } explicit Byte( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Byte( const Object &ob ) : Object( ob ) { validate(); } Byte( const std::string &v = "" ) : Object( PyBytes_FromStringAndSize( const_cast( v.c_str() ), 1 ), true ) { validate(); } Byte( char v ) : Object( PyBytes_FromStringAndSize( &v, 1 ), true ) { validate(); } // Assignment acquires new ownership of pointer Byte &operator=( const Object &rhs ) { return *this = *rhs; } Byte &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Assignment from C string Byte &operator=( const std::string &v ) { set( PyBytes_FromStringAndSize( const_cast( v.c_str() ), 1 ), true ); return *this; } Byte &operator=( char v ) { set( PyUnicode_FromStringAndSize( &v, 1 ), true ); return *this; } // Conversion operator Bytes() const; }; class PYCXX_EXPORT Bytes: public SeqBase { public: // Membership virtual bool accepts( PyObject *pyob ) const { return pyob != NULL && Py::_Bytes_Check( pyob ); } 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( PyBytes_FromStringAndSize( "", 0 ), true ) { validate(); } Bytes( const std::string &v ) : SeqBase( PyBytes_FromStringAndSize( const_cast( v.data() ), v.length() ), true ) { validate(); } Bytes( const std::string &v, Py_ssize_t vsize ) : SeqBase( PyBytes_FromStringAndSize( const_cast( v.data() ), vsize ), true ) { validate(); } Bytes( const char *v ) : SeqBase( PyBytes_FromString( v ), true ) { validate(); } Bytes( const char *v, Py_ssize_t vsize ) : SeqBase( PyBytes_FromStringAndSize( const_cast( v ), vsize ), true ) { validate(); } // Assignment acquires new ownership of pointer Bytes &operator=( const Object &rhs ) { return *this = *rhs; } Bytes &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Assignment from C string Bytes &operator=( const std::string &v ) { set( PyBytes_FromStringAndSize( const_cast( v.data() ), v.length() ), true ); return *this; } String decode( const char *encoding, const char *error="strict" ); // Queries virtual size_type size() const { return PyBytes_Size( ptr() ); } operator std::string() const { return as_std_string(); } std::string as_std_string() const { return std::string( PyBytes_AsString( ptr() ), static_cast( PyBytes_Size( ptr() ) ) ); } }; class PYCXX_EXPORT Char: public Object { public: // Membership virtual bool accepts( PyObject *pyob ) const { return (pyob != 0 && Py::_Unicode_Check( pyob ) && PySequence_Length( pyob ) == 1); } explicit Char( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Char( const Object &ob ) : Object( ob ) { validate(); } Char( int v ) : Object( PyUnicode_FromOrdinal( v ), true ) { validate(); } #if !defined( Py_LIMITED_API ) && !defined(Py_UNICODE_DEPRECATED) Char( Py_UNICODE v ) : Object( PyUnicode_FromOrdinal( v ), true ) { validate(); } #endif #if !defined( Py_LIMITED_API ) && !defined(Py_UNICODE_DEPRECATED) Char( const unicodestring &v ) : Object( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, const_cast( v.data() ),1 ), true ) { validate(); } #endif // Assignment acquires new ownership of pointer Char &operator=( const Object &rhs ) { return *this = *rhs; } Char &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } #if !defined( Py_LIMITED_API ) && !defined(Py_UNICODE_DEPRECATED) Char &operator=( const unicodestring &v ) { set( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, const_cast( v.data() ), 1 ), true ); return *this; } #endif #if !defined( Py_LIMITED_API ) && !defined(Py_UNICODE_DEPRECATED) Char &operator=( int v_ ) { Py_UNICODE v( v_ ); set( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, &v, 1 ), true ); return *this; } #endif #if !defined( Py_LIMITED_API ) && !defined(Py_UNICODE_DEPRECATED) Char &operator=( Py_UNICODE v ) { set( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, &v, 1 ), true ); return *this; } #endif long ord() { #if !defined( Py_LIMITED_API ) return static_cast( PyUnicode_ReadChar( ptr(), 0 ) ); #else // we know that a Char() is 1 unicode code point // that fits in 2 wchar_t on windows at worst wchar_t buf[2]; Py_ssize_t num_elements = PyUnicode_AsWideChar( ptr(), buf, 2 ); // just one wchar_t that easy if( num_elements == 1 ) { return static_cast( buf[0] ); } // must be a pair of utf-16 surragates - convert to a code point if( num_elements == 2 ) { // convert from utf-16 to a code-point return static_cast( ((buf[0]-0xd800)*0x400) + (buf[1]-0xdc00) + 0x10000); } return 0; #endif } // Conversion operator String() const; }; class PYCXX_EXPORT String: public SeqBase { public: virtual size_type capacity() const { return max_size(); } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob != NULL && Py::_Unicode_Check( pyob ); } explicit String( PyObject *pyob, bool owned = false ) : SeqBase( pyob, owned ) { validate(); } String( const Object &ob ) : SeqBase( ob ) { validate(); } String() : SeqBase( PyUnicode_FromString( "" ), true ) { validate(); } String( const char *latin1 ) : SeqBase( PyUnicode_FromString( latin1 ), true ) { validate(); } String( const std::string &latin1 ) : SeqBase( PyUnicode_FromStringAndSize( latin1.c_str(), latin1.size() ), true ) { validate(); } String( const char *latin1, Py_ssize_t size ) : SeqBase( PyUnicode_FromStringAndSize( latin1, size ), true ) { validate(); } /* [Taken from Pythons's unicode.h] Many of these APIs take two arguments encoding and errors. These parameters encoding and errors have the same semantics as the ones of the builtin unicode() API. Setting encoding to NULL causes the default encoding to be used. Error handling is set by errors which may also be set to NULL meaning to use the default handling defined for the codec. Default error handling for all builtin codecs is "strict" (ValueErrors are raised). The codecs all use a similar interface. Only deviation from the generic ones are documented. */ String( const std::string &s, const char *encoding, const char *errors=NULL ) : SeqBase( PyUnicode_Decode( s.c_str(), s.size(), encoding, errors ), true ) { validate(); } String( const char *s, const char *encoding, const char *errors=NULL ) : SeqBase( PyUnicode_Decode( s, strlen(s), encoding, errors ), true ) { validate(); } String( const char *s, Py_ssize_t size, const char *encoding, const char *errors=NULL ) : SeqBase( PyUnicode_Decode( s, size, encoding, errors ), true ) { validate(); } #if !defined( Py_LIMITED_API ) && !defined( Py_UNICODE_WIDE ) // Need these c'tors becuase Py_UNICODE is 2 bytes // User may use "int" or "unsigned int" as the unicode type String( const unsigned int *s, int length ) : SeqBase( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, reinterpret_cast( s ), length ), true ) { validate(); } String( const int *s, int length ) : SeqBase( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, reinterpret_cast( s ), length ), true ) { validate(); } #endif #if !defined( Py_LIMITED_API ) && !defined(Py_UNICODE_DEPRECATED) String( const Py_UNICODE *s, int length ) : SeqBase( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, s, length ), true ) { validate(); } #endif // Assignment acquires new ownership of pointer String &operator=( const Object &rhs ) { return *this = *rhs; } String &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } #if !defined( Py_LIMITED_API ) && !defined(Py_UNICODE_DEPRECATED) String &operator=( const unicodestring &v ) { set( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, const_cast( v.data() ), v.length() ), true ); return *this; } #endif #if !defined( Py_UNICODE_WIDE ) && !defined( Py_LIMITED_API ) String &operator=( const ucs4string &v ) { set( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, reinterpret_cast( v.data() ), v.length() ), true ); return *this; } #endif // Encode Bytes encode( const char *encoding, const char *error="strict" ) const { return Bytes( PyUnicode_AsEncodedString( ptr(), encoding, error ), true ); } #if !defined( Py_LIMITED_API ) // Queries virtual size_type size() const { return PyUnicode_GetLength( ptr() ); } #endif #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9 #if !defined( Py_LIMITED_API ) const Py_UNICODE *unicode_data() const { return PyUnicode_AS_UNICODE( ptr() ); } #endif #if !defined( Py_LIMITED_API ) unicodestring as_unicodestring() const { return unicodestring( unicode_data(), PyUnicode_GetLength( ptr() ) ); } #endif #endif ucs4string as_ucs4string() const { Py_UCS4 *buf = new Py_UCS4[ size() ]; if( PyUnicode_AsUCS4( ptr(), buf, size(), 0 ) == NULL ) { ifPyErrorThrowCxxException(); } ucs4string ucs4( reinterpret_cast(buf), size() ); delete[] buf; return ucs4; } operator std::string() const { // use the default encoding return as_std_string( NULL ); } std::string as_std_string( const char *encoding=NULL, const char *error="strict" ) const { Bytes b( encode( encoding, error ) ); return b.as_std_string(); } }; // ================================================== // class Tuple class PYCXX_EXPORT 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 ) { 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( size_type 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 ) { 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 ) { ifPyErrorThrowCxxException(); } } } // Assignment acquires new ownership of pointer Tuple &operator=( const Object &rhs ) { return *this = *rhs; } Tuple &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) 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 PYCXX_EXPORT TupleN: public Tuple { public: TupleN() : Tuple( (size_type)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 PYCXX_EXPORT 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( 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 ) { ifPyErrorThrowCxxException(); } } } // List from a sequence List( const Sequence &s ) : Sequence() { 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 ) { 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 ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_List_Check( pyob ); } List getSlice( Py_ssize_t i, Py_ssize_t j ) const { return List( PyList_GetSlice( ptr(), i, j ), true ); } void setSlice( Py_ssize_t i, Py_ssize_t j, const Object &v ) { if( PyList_SetSlice( ptr(), i, j, *v ) == -1 ) { ifPyErrorThrowCxxException(); } } void append( const Object &ob ) { if( PyList_Append( ptr(), *ob ) == -1 ) { ifPyErrorThrowCxxException(); } } void extend( const Object &ob ) { setSlice( size(), size(), ob ); } void insert( int i, const Object &ob ) { if( PyList_Insert( ptr(), i, *ob ) == -1 ) { ifPyErrorThrowCxxException(); } } void sort() { if( PyList_Sort( ptr() ) == -1 ) { ifPyErrorThrowCxxException(); } } void reverse() { if( PyList_Reverse( ptr() ) == -1 ) { 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 ) { 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 #if 0 // 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. } #endif 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 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 ) 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 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 char *key ) { return mapref( *this, key ); } mapref operator[]( const std::string &key ) { return mapref( *this, key ); } mapref operator[]( const Object &key ) { return mapref( *this, key ); } 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 ) { ifPyErrorThrowCxxException(); } } virtual void setItem( const std::string &s, const Object &ob ) { if( PyMapping_SetItemString( ptr(), const_cast( s.c_str() ), *ob ) == -1 ) { ifPyErrorThrowCxxException(); } } virtual void setItem( const Object &s, const Object &ob ) { if( PyObject_SetItem( ptr(), s.ptr(), ob.ptr() ) == -1 ) { ifPyErrorThrowCxxException(); } } void delItem( const std::string &s ) { if( PyMapping_DelItemString( ptr(), const_cast( s.c_str() ) ) == -1 ) { ifPyErrorThrowCxxException(); } } void delItem( const Object &s ) { if( PyMapping_DelItem( ptr(), *s ) == -1 ) { ifPyErrorThrowCxxException(); } } // Queries List keys() const { return List( PyMapping_Keys( ptr() ), true ); } List values() const { // each returned item is a (key, value) pair return List( PyMapping_Values( ptr() ), true ); } List items() const { return List( PyMapping_Items( ptr() ), true ); } 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 sequence_index_type pos; // index into the keys public: ~iterator() {} iterator() : map( 0 ) , keys() , pos( 0 ) {} iterator( MapBase *m, bool end = false ) : map( m ) , keys( m->keys() ) , pos( end ? keys.length() : 0 ) {} iterator( const iterator &other ) : map( other.map ) , keys( other.keys ) , pos( other.pos ) {} iterator( MapBase *map_, List keys_, size_type pos_ ) : map( map_ ) , keys( keys_ ) , pos( pos_ ) {} reference operator*() { Object key = keys[ pos ]; return std::make_pair( key, mapref( *map, key ) ); } iterator &operator=( const iterator &other ) { if( this != &other ) { map = other.map; keys = other.keys; pos = other.pos; } return *this; } bool eql( const iterator &other ) const { return map->ptr() == other.map->ptr() && pos == other.pos; } bool neq( const iterator &other ) const { return map->ptr() != other.map->ptr() || pos != other.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, false ); } 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 Py_ssize_t pos; // index into the keys public: ~const_iterator() {} const_iterator() : map( 0 ) , keys() , pos() {} const_iterator( const MapBase *m, List k, Py_ssize_t p ) : map( m ) , keys( k ) , pos( p ) {} const_iterator( const const_iterator &other ) : map( other.map ) , keys( other.keys ) , pos( other.pos ) {} bool eql( const const_iterator &other ) const { return map->ptr() == other.map->ptr() && pos == other.pos; } bool neq( const const_iterator &other ) const { return map->ptr() != other.map->ptr() || pos != other.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 ) { 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, keys(), 0 ); } const_iterator end() const { return const_iterator( this, keys(), length() ); } }; // 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 ); PYCXX_EXPORT extern bool operator==( const Mapping::iterator &left, const Mapping::iterator &right ); PYCXX_EXPORT extern bool operator!=( const Mapping::iterator &left, const Mapping::iterator &right ); PYCXX_EXPORT extern bool operator==( const Mapping::const_iterator &left, const Mapping::const_iterator &right ); PYCXX_EXPORT extern bool operator!=( const Mapping::const_iterator &left, const Mapping::const_iterator &right ); // ================================================== // class Dict class PYCXX_EXPORT Dict: public Mapping { public: // Constructor explicit Dict( PyObject *pyob, bool owned=false ) : Mapping( pyob, owned ) { validate(); } 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 ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Dict_Check( pyob ); } }; class PYCXX_EXPORT 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 ) { set( rhsp ); } return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && PyCallable_Check( pyob ); } // Call Object apply( const Tuple &args ) const { 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 { #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 9 PyObject *result = PyObject_Call( ptr(), args.ptr(), kw.ptr() ); #else PyObject *result = PyEval_CallObjectWithKeywords( ptr(), args.ptr(), kw.ptr() ); #endif if( result == NULL ) { ifPyErrorThrowCxxException(); } return asObject( result ); } #if (!defined( Py_LIMITED_API ) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 9) || (defined( Py_LIMITED_API ) && Py_LIMITED_API+0 >= 0x03090000) Object apply() const { PyObject *result = PyObject_CallNoArgs( ptr() ); return asObject( result ); } Object apply( PyObject *pargs ) const { if( pargs == 0 ) { return apply( Tuple() ); } else { return apply( Tuple( pargs ) ); } } #else Object apply( PyObject *pargs = 0 ) const { if( pargs == 0 ) { return apply( Tuple() ); } else { return apply( Tuple( pargs ) ); } } #endif }; class PYCXX_EXPORT 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 ) set( rhsp ); return *this; } Dict getDict() const { 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 ) ); return target.apply(); } 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 ) ); } //------------------------------------------------------------ // operator + 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, *Long( j ) ) ); } inline Object operator+( const Object &a, long j ) { return asObject( PyNumber_Add( *a, *Long( 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( *Long( j ), *b ) ); } inline Object operator+( long j, const Object &b ) { return asObject( PyNumber_Add( *Long( j ), *b ) ); } inline Object operator+( double v, const Object &b ) { return asObject( PyNumber_Add( *Float( v ), *b ) ); } //------------------------------------------------------------ // operator - 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, *Long( 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( *Long( j ), *b ) ); } inline Object operator-( double v, const Object &b ) { return asObject( PyNumber_Subtract( *Float( v ), *b ) ); } //------------------------------------------------------------ // operator * 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, *Long( 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( *Long( j ), *b ) ); } inline Object operator*( double v, const Object &b ) { return asObject( PyNumber_Multiply( *Float( v ), *b ) ); } //------------------------------------------------------------ // operator / inline Object operator/( const Object &a, const Object &b ) { return asObject( PyNumber_TrueDivide( *a, *b ) ); } inline Object operator/( const Object &a, int j ) { return asObject( PyNumber_TrueDivide( *a, *Long( j ) ) ); } inline Object operator/( const Object &a, double v ) { return asObject( PyNumber_TrueDivide( *a, *Float( v ) ) ); } inline Object operator/( int j, const Object &b ) { return asObject( PyNumber_TrueDivide( *Long( j ), *b ) ); } inline Object operator/( double v, const Object &b ) { return asObject( PyNumber_TrueDivide( *Float( v ), *b ) ); } //------------------------------------------------------------ // operator % 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, *Long( 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( *Long( j ), *b ) ); } inline Object operator%( double v, const Object &b ) { return asObject( PyNumber_Remainder( *Float( v ), *b ) ); } //------------------------------------------------------------ // type 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 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 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