//-----------------------------------------------------------------------------
//
// 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/Config.hxx"
#include "CXX/Exception.hxx"
#include
#include STR_STREAM
#include
#include
#include
#include
namespace Py
{
typedef int 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;
// 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();
}
MyType(const Object& other): Object(other.ptr()) {
validate();
}
*/
// Alernate version for the constructor to allow for construction from owned pointers:
/*
explicit MyType (PyObject *pyob): Object(pyob) {
validate();
}
*/
// You may wish to add other constructors; see the classes below for examples.
// Each constructor must use "set" to set the pointer
// and end by validating the pointer you have created.
// (4) Each class needs at least these two assignment operators:
/*
MyType& operator= (const Object& rhs) {
return (*this = *rhs);
}
Mytype& operator= (PyObject* rhsp) {
if(ptr() == rhsp) return *this;
set(rhsp);
return *this;
}
*/
// Note on accepts: constructors call the base class
// version of a virtual when calling the base class constructor,
// so the test has to be done explicitly in a descendent.
// If you are inheriting from PythonExtension 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();
public:
// Constructor acquires new ownership of pointer unless explicitly told not to.
explicit Object (PyObject* pyob=Py::_None(), bool owned = false): p (pyob)
{
if(!owned)
{
Py::_XINCREF (p);
}
validate();
}
// Copy constructor acquires new ownership of pointer
Object (const Object& ob): p(ob.p)
{
Py::_XINCREF (p);
validate();
}
// Assignment acquires new ownership of pointer
Object& operator= (const Object& rhs)
{
set(rhs.p);
return *this;
}
Object& operator= (PyObject* rhsp)
{
if(ptr() == rhsp) return *this;
set (rhsp);
return *this;
}
// Destructor
virtual ~Object ()
{
release ();
}
// Loaning the pointer to others, retain ownership
PyObject* operator* () const
{
return p;
}
// Explicit reference_counting changes
void increment_reference_count()
{
Py::_XINCREF(p);
}
void decrement_reference_count()
{
// not allowed to commit suicide, however
if(reference_count() == 1)
throw RuntimeError("Object::decrement_reference_count error.");
Py::_XDECREF(p);
}
// Would like to call this pointer() but messes up STL in SeqBase
PyObject* ptr () const
{
return p;
}
//
// Queries
//
// Can pyob be used in this object's constructor?
virtual bool accepts (PyObject *pyob) const
{
return (pyob != 0);
}
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 getItem (const Object& key) const
{
return Object (PyObject_GetItem(p, *key), true);
}
long hashValue () const
{
return PyObject_Hash (p);
}
//
// int print (FILE* fp, int flags=Py_Print_RAW)
//{
// return PyObject_Print (p, fp, flags);
//}
//
bool is(PyObject *pother) const
{ // identity test
return p == pother;
}
bool is(const Object& other) const
{ // identity test
return p == other.p;
}
bool isNone() const
{
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);
}
// 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.");
}
void delAttr (const std::string& s)
{
if(PyObject_DelAttrString (p, const_cast(s.c_str())) == -1)
throw AttributeError ("delAttr failed.");
}
// PyObject_SetItem is too weird to be using from C++
// so it is intentionally omitted.
void delItem (const Object& key)
{
//if(PyObject_DelItem(p, *key) == -1)
// failed to link on Windows?
throw KeyError("delItem failed.");
}
// Equality and comparison use PyObject_RichCompareBool
bool operator==(const Object& o2) const
{
int k = PyObject_RichCompareBool (p, *o2, Py_EQ);
if (PyErr_Occurred()) throw Exception();
return k != 0;
}
bool operator!=(const Object& o2) const
{
int k = PyObject_RichCompareBool (p, *o2, Py_NE);
if (PyErr_Occurred()) throw Exception();
return k != 0;
}
bool operator>=(const Object& o2) const
{
int k = PyObject_RichCompareBool (p, *o2, Py_GE);
if (PyErr_Occurred()) throw Exception();
return k != 0;
}
bool operator<=(const Object& o2) const
{
int k = PyObject_RichCompareBool (p, *o2, Py_LE);
if (PyErr_Occurred()) throw Exception();
return k != 0;
}
bool operator<(const Object& o2) const
{
int k = PyObject_RichCompareBool (p, *o2, Py_LT);
if (PyErr_Occurred()) throw Exception();
return k != 0;
}
bool operator>(const Object& o2) const
{
int k = PyObject_RichCompareBool (p, *o2, Py_GT);
if (PyErr_Occurred()) throw Exception();
return k != 0;
}
};
// End of class Object
inline PyObject* new_reference_to(const Object& g)
{
PyObject* p = g.ptr();
Py::_XINCREF(p);
return p;
}
// Nothing() is what an extension method returns if
// there is no other return value.
inline Object Nothing()
{
return Object(Py::_None());
}
// Python special None value
inline Object None()
{
return Object(Py::_None());
}
// 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)
{
set(*ob, true);
validate();
}
// Assignment acquires new ownership of pointer
Boolean& operator= (const Object& rhs)
{
return (*this = *rhs);
}
Boolean& operator= (PyObject* rhsp)
{
if(ptr() == rhsp) return *this;
set (rhsp, true);
return *this;
}
// Membership
virtual bool accepts (PyObject *pyob) const
{
return pyob && Py::_Boolean_Check (pyob);
}
// 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
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();
}
// 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)
{
validate();
}
Long (const Long& ob): Object(ob.ptr())
{
validate();
}
// create from long
explicit Long (long v = 0L)
: Object(PyLong_FromLong(v), true)
{
validate();
}
// create from 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();
}
// try to create from any object
Long (const Object& ob)
: Object(PyNumber_Long(*ob), true)
{
validate();
}
// Assignment acquires new ownership of pointer
Long& operator= (const Object& rhs)
{
return (*this = *rhs);
}
Long& operator= (PyObject* rhsp)
{
if(ptr() == rhsp) return *this;
set (PyNumber_Long(rhsp), true);
return *this;
}
// Membership
virtual bool accepts (PyObject *pyob) const
{
return pyob && Py::_Long_Check (pyob);
}
// convert to long
operator long() const
{
return PyLong_AsLong (ptr());
}
// convert to unsigned
operator unsigned long() const
{
return PyLong_AsUnsignedLong (ptr());
}
operator double() const
{
return PyLong_AsDouble (ptr());
}
// assign from an int
Long& operator= (int v)
{
set(PyLong_FromLong (long(v)), true);
return *this;
}
// assign from long
Long& operator= (long v)
{
set(PyLong_FromLong (v), true);
return *this;
}
// assign from unsigned long
Long& operator= (unsigned long v)
{
set(PyLong_FromUnsignedLong (v), true);
return *this;
}
};
#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 (PY_LONG_LONG v = 0L)
: Object(PyLong_FromLongLong(v), true)
{
validate();
}
// create from unsigned long long
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)
{
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 PY_LONG_LONG() const
{
return PyLong_AsLongLong (ptr());
}
// convert to unsigned long
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= (PY_LONG_LONG v)
{
set(PyLong_FromLongLong (v), true);
return *this;
}
// assign from unsigned long long
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
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( NULL )
, 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 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; // ?
}
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) return *this;
set (rhsp);
return *this;
}
virtual bool accepts (PyObject *pyob) const
{
return pyob && PySequence_Check (pyob);
}
size_type length () const
{
return PySequence_Length (ptr());
}
// Element access
const T operator[](sequence_index_type index) const
{
return getItem(index);
}
seqref 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();
}
}
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);
}
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 random_access_iterator_parent(seqref)
{
protected:
friend class SeqBase;
SeqBase* seq;
int count;
public:
~iterator ()
{}
iterator ()
: seq( 0 )
, count( 0 )
{}
iterator (SeqBase* s, int where)
: seq( s )
, count( where )
{}
iterator (const iterator& other)
: seq( other.seq )
, count( other.count )
{}
bool eql (const iterator& other) const
{
return (seq->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) return *this;
seq = other.seq;
count = other.count;
return *this;
}
iterator operator+(int n) const
{
return iterator(seq, count + n);
}
iterator operator-(int n) const
{
return iterator(seq, count - n);
}
iterator& operator+=(int n)
{
count = count + n;
return *this;
}
iterator& operator-=(int n)
{
count = count - n;
return *this;
}
int operator-(const iterator& other) const
{
if (*seq != *other.seq)
throw RuntimeError ("SeqBase::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 random_access_iterator_parent(const Object)
{
protected:
friend class SeqBase;
const SeqBase* seq;
sequence_index_type count;
private:
const_iterator (const SeqBase* s, int where)
: seq( s )
, count( where )
{}
public:
~const_iterator ()
{}
const_iterator ()
: seq( 0 )
, count( 0 )
{}
const_iterator(const const_iterator& other)
: seq( other.seq )
, count( other.count )
{}
const T operator*() const
{
return seq->getItem(count);
}
const T operator[] (sequence_index_type i) const
{
return seq->getItem(count + i);
}
const_iterator& operator=(const const_iterator& other)
{
if (this == &other) return *this;
seq = other.seq;
count = other.count;
return *this;
}
const_iterator operator+(int n) const
{
return const_iterator(seq, count + n);
}
bool eql (const const_iterator& other) const
{
return (seq->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-(int n)
{
return const_iterator(seq, count - n);
}
const_iterator& operator+=(int n)
{
count = count + n;
return *this;
}
const_iterator& operator-=(int n)
{
count = count - n;
return *this;
}
int operator-(const const_iterator& other) const
{
if (*seq != *other.seq)
throw RuntimeError ("SeqBase::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