You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2805 lines
59 KiB
2805 lines
59 KiB
//----------------------------------*-C++-*----------------------------------//
|
|
// Copyright 1998 The Regents of the University of California.
|
|
// All rights reserved. See LEGAL.LLNL for full text and disclaimer.
|
|
//---------------------------------------------------------------------------//
|
|
|
|
#ifndef __CXX_Objects__h
|
|
#define __CXX_Objects__h
|
|
|
|
// Prevent warnings
|
|
#if defined(_XOPEN_SOURCE)
|
|
#undef _XOPEN_SOURCE
|
|
#endif
|
|
|
|
#include "Python.h"
|
|
#include "Config.hxx"
|
|
#include "Exception.hxx"
|
|
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <iterator>
|
|
#include <utility>
|
|
#include <typeinfo>
|
|
|
|
namespace Py
|
|
{
|
|
typedef int sequence_index_type; // type of an index into a sequence
|
|
|
|
// Forward declarations
|
|
class Object;
|
|
class Type;
|
|
template<typename T> class SeqBase;
|
|
class String;
|
|
class List;
|
|
template<typename T> class MapBase;
|
|
|
|
// new_reference_to also overloaded below on Object
|
|
inline PyObject* new_reference_to(PyObject* p)
|
|
{
|
|
Py::_XINCREF(p);
|
|
return p;
|
|
}
|
|
|
|
// returning Null() from an extension method triggers a
|
|
// Python exception
|
|
inline PyObject* Null()
|
|
{
|
|
return (static_cast<PyObject*>(0));
|
|
}
|
|
|
|
//===========================================================================//
|
|
// class Object
|
|
// The purpose of this class is to serve as the most general kind of
|
|
// Python object, for the purpose of writing C++ extensions in Python
|
|
// Objects hold a PyObject* which they own. This pointer is always a
|
|
// valid pointer to a Python object. In children we must maintain this behavior.
|
|
//
|
|
// Instructions on how to make your own class MyType descended from Object:
|
|
// (0) Pick a base class, either Object or perhaps SeqBase<T> or MapBase<T>.
|
|
// This example assumes Object.
|
|
|
|
// (1) Write a routine int MyType_Check (PyObject *) modeled after PyInt_Check,
|
|
// PyFloat_Check, etc.
|
|
|
|
// (2) Add method accepts:
|
|
// virtual bool accepts (PyObject *pyob) const {
|
|
// return pyob && MyType_Check (pyob);
|
|
// }
|
|
|
|
// (3) Include the following constructor and copy constructor
|
|
//
|
|
/*
|
|
explicit MyType (PyObject *pyob): Object(pyob) {
|
|
validate();
|
|
}
|
|
|
|
MyType(const Object& other): Object(other.ptr()) {
|
|
validate();
|
|
}
|
|
*/
|
|
|
|
// Alernate version for the constructor to allow for construction from owned pointers:
|
|
/*
|
|
explicit MyType (PyObject *pyob): Object(pyob) {
|
|
validate();
|
|
}
|
|
*/
|
|
|
|
// You may wish to add other constructors; see the classes below for examples.
|
|
// Each constructor must use "set" to set the pointer
|
|
// and end by validating the pointer you have created.
|
|
|
|
// (4) Each class needs at least these two assignment operators:
|
|
/*
|
|
MyType& operator= (const Object& rhs) {
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Mytype& operator= (PyObject* rhsp) {
|
|
if(ptr() == rhsp) return *this;
|
|
set(rhsp);
|
|
return *this;
|
|
}
|
|
*/
|
|
// Note on accepts: constructors call the base class
|
|
// version of a virtual when calling the base class constructor,
|
|
// so the test has to be done explicitly in a descendent.
|
|
|
|
// If you are inheriting from PythonExtension<T> to define an object
|
|
// note that it contains PythonExtension<T>::check
|
|
// which you can use in accepts when writing a wrapper class.
|
|
// See Demo/range.h and Demo/range.cxx for an example.
|
|
|
|
class Object
|
|
{
|
|
private:
|
|
// the pointer to the Python object
|
|
// Only Object sets this directly.
|
|
// The default constructor for Object sets it to Py_None and
|
|
// child classes must use "set" to set it
|
|
//
|
|
PyObject* p;
|
|
|
|
protected:
|
|
|
|
void set (PyObject* pyob, bool owned = false)
|
|
{
|
|
release();
|
|
p = pyob;
|
|
if (!owned)
|
|
{
|
|
Py::_XINCREF (p);
|
|
}
|
|
validate();
|
|
}
|
|
|
|
void release ()
|
|
{
|
|
Py::_XDECREF (p);
|
|
p = 0;
|
|
}
|
|
|
|
void validate()
|
|
{
|
|
// release pointer if not the right type
|
|
if (! accepts (p))
|
|
{
|
|
release ();
|
|
if(PyErr_Occurred())
|
|
{ // Error message already set
|
|
throw Exception();
|
|
}
|
|
// Better error message if RTTI available
|
|
#if defined( _CPPRTTI )
|
|
std::string s("Error creating object of type ");
|
|
s += (typeid (*this)).name();
|
|
throw TypeError (s);
|
|
#else
|
|
throw TypeError ("CXX: type error.");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public:
|
|
// Constructor acquires new ownership of pointer unless explicitly told not to.
|
|
explicit Object (PyObject* pyob=Py::_None(), bool owned = false): p (pyob)
|
|
{
|
|
if(!owned)
|
|
{
|
|
Py::_XINCREF (p);
|
|
}
|
|
validate();
|
|
}
|
|
|
|
// Copy constructor acquires new ownership of pointer
|
|
Object (const Object& ob): p(ob.p)
|
|
{
|
|
Py::_XINCREF (p);
|
|
validate();
|
|
}
|
|
|
|
// Assignment acquires new ownership of pointer
|
|
Object& operator= (const Object& rhs)
|
|
{
|
|
set(rhs.p);
|
|
return *this;
|
|
}
|
|
|
|
Object& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
|
|
// Destructor
|
|
virtual ~Object ()
|
|
{
|
|
release ();
|
|
}
|
|
|
|
// Loaning the pointer to others, retain ownership
|
|
PyObject* operator* () const
|
|
{
|
|
return p;
|
|
}
|
|
|
|
// Explicit reference_counting changes
|
|
void increment_reference_count()
|
|
{
|
|
Py::_XINCREF(p);
|
|
}
|
|
|
|
void decrement_reference_count()
|
|
{
|
|
// not allowed to commit suicide, however
|
|
if(reference_count() == 1)
|
|
throw RuntimeError("Object::decrement_reference_count error.");
|
|
Py::_XDECREF(p);
|
|
}
|
|
// Would like to call this pointer() but messes up STL in SeqBase<T>
|
|
PyObject* ptr () const
|
|
{
|
|
return p;
|
|
}
|
|
|
|
//
|
|
// Queries
|
|
//
|
|
|
|
// Can pyob be used in this object's constructor?
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return (pyob != 0);
|
|
}
|
|
|
|
int reference_count () const
|
|
{ // the reference count
|
|
return p ? p->ob_refcnt : 0;
|
|
}
|
|
|
|
Type type () const; // the type object associated with this one
|
|
|
|
String str () const; // the str() representation
|
|
|
|
std::string as_string() const;
|
|
|
|
String repr () const; // the repr () representation
|
|
|
|
List dir () const; // the dir() list
|
|
|
|
bool hasAttr (const std::string& s) const
|
|
{
|
|
return PyObject_HasAttrString (p, const_cast<char*>(s.c_str())) ? true: false;
|
|
}
|
|
|
|
Object getAttr (const std::string& s) const
|
|
{
|
|
return Object (PyObject_GetAttrString (p, const_cast<char*>(s.c_str())), true);
|
|
}
|
|
|
|
Object getItem (const Object& key) const
|
|
{
|
|
return Object (PyObject_GetItem(p, *key), true);
|
|
}
|
|
|
|
long hashValue () const
|
|
{
|
|
return PyObject_Hash (p);
|
|
}
|
|
|
|
//
|
|
// int print (FILE* fp, int flags=Py_Print_RAW)
|
|
// {
|
|
// return PyObject_Print (p, fp, flags);
|
|
// }
|
|
//
|
|
bool is(PyObject *pother) const
|
|
{ // identity test
|
|
return p == pother;
|
|
}
|
|
|
|
bool is(const Object& other) const
|
|
{ // identity test
|
|
return p == other.p;
|
|
}
|
|
|
|
bool isCallable () const
|
|
{
|
|
return PyCallable_Check (p) != 0;
|
|
}
|
|
|
|
bool isInstance () const
|
|
{
|
|
return PyInstance_Check (p) != 0;
|
|
}
|
|
|
|
bool isDict () const
|
|
{
|
|
return Py::_Dict_Check (p);
|
|
}
|
|
|
|
bool isList () const
|
|
{
|
|
return Py::_List_Check (p);
|
|
}
|
|
|
|
bool isMapping () const
|
|
{
|
|
return PyMapping_Check (p) != 0;
|
|
}
|
|
|
|
bool isNumeric () const
|
|
{
|
|
return PyNumber_Check (p) != 0;
|
|
}
|
|
|
|
bool isSequence () const
|
|
{
|
|
return PySequence_Check (p) != 0;
|
|
}
|
|
|
|
bool isTrue () const
|
|
{
|
|
return PyObject_IsTrue (p) != 0;
|
|
}
|
|
|
|
bool isType (const Type& t) const;
|
|
|
|
bool isTuple() const
|
|
{
|
|
return Py::_Tuple_Check(p);
|
|
}
|
|
|
|
bool isString() const
|
|
{
|
|
return Py::_String_Check(p) || Py::_Unicode_Check(p);
|
|
}
|
|
|
|
bool isUnicode() const
|
|
{
|
|
return Py::_Unicode_Check(p);
|
|
}
|
|
|
|
// Commands
|
|
void setAttr (const std::string& s, const Object& value)
|
|
{
|
|
if(PyObject_SetAttrString (p, const_cast<char*>(s.c_str()), *value) == -1)
|
|
throw AttributeError ("getAttr failed.");
|
|
}
|
|
|
|
void delAttr (const std::string& s)
|
|
{
|
|
if(PyObject_DelAttrString (p, const_cast<char*>(s.c_str())) == -1)
|
|
throw AttributeError ("delAttr failed.");
|
|
}
|
|
|
|
// PyObject_SetItem is too weird to be using from C++
|
|
// so it is intentionally omitted.
|
|
|
|
void delItem (const Object& /*key*/)
|
|
{
|
|
//if(PyObject_DelItem(p, *key) == -1)
|
|
// failed to link on Windows?
|
|
throw KeyError("delItem failed.");
|
|
}
|
|
// Equality and comparison use PyObject_Compare
|
|
|
|
bool operator==(const Object& o2) const
|
|
{
|
|
int k = PyObject_Compare (p, *o2);
|
|
if (PyErr_Occurred()) throw Exception();
|
|
return k == 0;
|
|
}
|
|
|
|
bool operator!=(const Object& o2) const
|
|
{
|
|
int k = PyObject_Compare (p, *o2);
|
|
if (PyErr_Occurred()) throw Exception();
|
|
return k != 0;
|
|
|
|
}
|
|
|
|
bool operator>=(const Object& o2) const
|
|
{
|
|
int k = PyObject_Compare (p, *o2);
|
|
if (PyErr_Occurred()) throw Exception();
|
|
return k >= 0;
|
|
}
|
|
|
|
bool operator<=(const Object& o2) const
|
|
{
|
|
int k = PyObject_Compare (p, *o2);
|
|
if (PyErr_Occurred()) throw Exception();
|
|
return k <= 0;
|
|
}
|
|
|
|
bool operator<(const Object& o2) const
|
|
{
|
|
int k = PyObject_Compare (p, *o2);
|
|
if (PyErr_Occurred()) throw Exception();
|
|
return k < 0;
|
|
}
|
|
|
|
bool operator>(const Object& o2) const
|
|
{
|
|
int k = PyObject_Compare (p, *o2);
|
|
if (PyErr_Occurred()) throw Exception();
|
|
return k > 0;
|
|
}
|
|
};
|
|
// End of class Object
|
|
inline PyObject* new_reference_to(const Object& g)
|
|
{
|
|
PyObject* p = g.ptr();
|
|
Py::_XINCREF(p);
|
|
return p;
|
|
}
|
|
|
|
// Nothing() is what an extension method returns if
|
|
// there is no other return value.
|
|
inline Object Nothing()
|
|
{
|
|
return Object(Py::_None());
|
|
}
|
|
|
|
// Python special None value
|
|
inline Object None()
|
|
{
|
|
return Object(Py::_None());
|
|
}
|
|
|
|
// TMM: 31May'01 - Added the #ifndef so I can exlude iostreams.
|
|
#ifndef CXX_NO_IOSTREAMS
|
|
std::ostream& operator<< (std::ostream& os, const Object& ob);
|
|
#endif
|
|
|
|
// Class Type
|
|
class Type: public Object
|
|
{
|
|
public:
|
|
explicit Type (PyObject* pyob, bool owned = false): Object(pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Type (const Object& ob): Object(*ob)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Type(const Type& t): Object(t)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Type& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Type& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && Py::_Type_Check (pyob);
|
|
}
|
|
};
|
|
|
|
|
|
//
|
|
// Convert an owned Python pointer into a CXX Object
|
|
//
|
|
inline Object asObject (PyObject *p)
|
|
{
|
|
return Object(p, true);
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===============================================
|
|
// class Int
|
|
class Int: public Object
|
|
{
|
|
public:
|
|
// Constructor
|
|
explicit Int (PyObject *pyob, bool owned = false): Object (pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Int (const Int& ob): Object(*ob)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// create from long
|
|
explicit Int (long v = 0L): Object(PyInt_FromLong(v), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// create from int
|
|
explicit Int (int v)
|
|
{
|
|
long w = v;
|
|
set(PyInt_FromLong(w), true);
|
|
validate();
|
|
}
|
|
|
|
Int (const Object& ob)
|
|
{
|
|
set(PyNumber_Int(*ob), true);
|
|
validate();
|
|
}
|
|
|
|
// Assignment acquires new ownership of pointer
|
|
|
|
Int& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Int& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (PyNumber_Int(rhsp), true);
|
|
return *this;
|
|
}
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && Py::_Int_Check (pyob);
|
|
}
|
|
// convert to long
|
|
operator long() const
|
|
{
|
|
return PyInt_AsLong (ptr());
|
|
}
|
|
// assign from an int
|
|
Int& operator= (int v)
|
|
{
|
|
set (PyInt_FromLong (long(v)), true);
|
|
return *this;
|
|
}
|
|
// assign from long
|
|
Int& operator= (long v)
|
|
{
|
|
set (PyInt_FromLong (v), true);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
// ===============================================
|
|
// class Long
|
|
class Long: public Object
|
|
{
|
|
public:
|
|
// Constructor
|
|
explicit Long (PyObject *pyob, bool owned = false): Object (pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Long (const Long& ob): Object(ob.ptr())
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// create from long
|
|
explicit Long (long v = 0L)
|
|
: Object(PyLong_FromLong(v), true)
|
|
{
|
|
validate();
|
|
}
|
|
// create from int
|
|
explicit Long (int v)
|
|
: Object(PyLong_FromLong(static_cast<long>(v)), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// create from unsigned long
|
|
explicit Long (unsigned long v)
|
|
: Object(PyLong_FromUnsignedLong(v), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// try to create from any object
|
|
Long (const Object& ob)
|
|
: Object(PyNumber_Long(*ob), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// Assignment acquires new ownership of pointer
|
|
|
|
Long& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Long& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (PyNumber_Long(rhsp), true);
|
|
return *this;
|
|
}
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && Py::_Long_Check (pyob);
|
|
}
|
|
// convert to long
|
|
operator long() const
|
|
{
|
|
return PyLong_AsLong (ptr());
|
|
}
|
|
operator double() const
|
|
{
|
|
return PyLong_AsDouble (ptr());
|
|
}
|
|
operator unsigned long() const
|
|
{
|
|
return PyLong_AsUnsignedLong (ptr());
|
|
}
|
|
// assign from an int
|
|
Long& operator= (int v)
|
|
{
|
|
set(PyLong_FromLong (long(v)), true);
|
|
return *this;
|
|
}
|
|
// assign from long
|
|
Long& operator= (long v)
|
|
{
|
|
set(PyLong_FromLong (v), true);
|
|
return *this;
|
|
}
|
|
// assign from unsigned long
|
|
Long& operator= (unsigned long v)
|
|
{
|
|
set(PyLong_FromUnsignedLong (v), true);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
// ===============================================
|
|
// class Float
|
|
//
|
|
class Float: public Object
|
|
{
|
|
public:
|
|
// Constructor
|
|
explicit Float (PyObject *pyob, bool owned = false): Object(pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Float (const Float& f): Object(f)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// make from double
|
|
explicit Float (double v=0.0)
|
|
: Object(PyFloat_FromDouble (v), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// try to make from any object
|
|
Float (const Object& ob)
|
|
: Object(PyNumber_Float(*ob), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Float& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Float& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (PyNumber_Float(rhsp), true);
|
|
return *this;
|
|
}
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && Py::_Float_Check (pyob);
|
|
}
|
|
// convert to double
|
|
operator double () const
|
|
{
|
|
return PyFloat_AsDouble (ptr());
|
|
}
|
|
// assign from a double
|
|
Float& operator= (double v)
|
|
{
|
|
set(PyFloat_FromDouble (v), true);
|
|
return *this;
|
|
}
|
|
// assign from an int
|
|
Float& operator= (int v)
|
|
{
|
|
set(PyFloat_FromDouble (double(v)), true);
|
|
return *this;
|
|
}
|
|
// assign from long
|
|
Float& operator= (long v)
|
|
{
|
|
set(PyFloat_FromDouble (double(v)), true);
|
|
return *this;
|
|
}
|
|
// assign from an Int
|
|
Float& operator= (const Int& iob)
|
|
{
|
|
set(PyFloat_FromDouble (double(long(iob))), true);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
// ===============================================
|
|
// class Complex
|
|
class Complex: public Object
|
|
{
|
|
public:
|
|
// Constructor
|
|
explicit Complex (PyObject *pyob, bool owned = false): Object(pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Complex (const Complex& f): Object(f)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// make from double
|
|
explicit Complex (double v=0.0, double w=0.0)
|
|
:Object(PyComplex_FromDoubles (v, w), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Complex& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Complex& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && Py::_Complex_Check (pyob);
|
|
}
|
|
// convert to Py_complex
|
|
operator Py_complex () const
|
|
{
|
|
return PyComplex_AsCComplex (ptr());
|
|
}
|
|
// assign from a Py_complex
|
|
Complex& operator= (const Py_complex& v)
|
|
{
|
|
set(PyComplex_FromCComplex (v), true);
|
|
return *this;
|
|
}
|
|
// assign from a double
|
|
Complex& operator= (double v)
|
|
{
|
|
set(PyComplex_FromDoubles (v, 0.0), true);
|
|
return *this;
|
|
}
|
|
// assign from an int
|
|
Complex& operator= (int v)
|
|
{
|
|
set(PyComplex_FromDoubles (double(v), 0.0), true);
|
|
return *this;
|
|
}
|
|
// assign from long
|
|
Complex& operator= (long v)
|
|
{
|
|
set(PyComplex_FromDoubles (double(v), 0.0), true);
|
|
return *this;
|
|
}
|
|
// assign from an Int
|
|
Complex& operator= (const Int& iob)
|
|
{
|
|
set(PyComplex_FromDoubles (double(long(iob)), 0.0), true);
|
|
return *this;
|
|
}
|
|
|
|
double real() const
|
|
{
|
|
return PyComplex_RealAsDouble(ptr());
|
|
}
|
|
|
|
double imag() const
|
|
{
|
|
return PyComplex_ImagAsDouble(ptr());
|
|
}
|
|
};
|
|
// Sequences
|
|
// Sequences are here represented as sequences of items of type T.
|
|
// The base class SeqBase<T> represents that.
|
|
// In basic Python T is always "Object".
|
|
|
|
// seqref<T> is what you get if you get elements from a non-const SeqBase<T>.
|
|
// Note: seqref<T> could probably be a nested class in SeqBase<T> but that might stress
|
|
// some compilers needlessly. Simlarly for mapref later.
|
|
|
|
// While this class is not intended for enduser use, it needs some public
|
|
// constructors for the benefit of the STL.
|
|
|
|
// See Scott Meyer's More Essential C++ for a description of proxies.
|
|
// This application is even more complicated. We are doing an unusual thing
|
|
// in having a double proxy. If we want the STL to work
|
|
// properly we have to compromise by storing the rvalue inside. The
|
|
// entire Object API is repeated so that things like s[i].isList() will
|
|
// work properly.
|
|
|
|
// Still, once in a while a weird compiler message may occur using expressions like x[i]
|
|
// Changing them to Object(x[i]) helps the compiler to understand that the
|
|
// conversion of a seqref to an Object is wanted.
|
|
|
|
template<typename T>
|
|
class seqref
|
|
{
|
|
protected:
|
|
SeqBase<T>& s; // the sequence
|
|
int offset; // item number
|
|
T the_item; // lvalue
|
|
public:
|
|
|
|
seqref (SeqBase<T>& seq, sequence_index_type j)
|
|
: s(seq), offset(j), the_item (s.getItem(j))
|
|
{}
|
|
|
|
seqref (const seqref<T>& range)
|
|
: s(range.s), offset(range.offset), the_item(range.the_item)
|
|
{}
|
|
|
|
// TMM: added this seqref ctor for use with STL algorithms
|
|
seqref (Object& obj)
|
|
: s(dynamic_cast< SeqBase<T>&>(obj))
|
|
, offset( NULL )
|
|
, the_item(s.getItem(offset))
|
|
{}
|
|
~seqref()
|
|
{}
|
|
|
|
operator T() const
|
|
{ // rvalue
|
|
return the_item;
|
|
}
|
|
|
|
seqref<T>& operator=(const seqref<T>& rhs)
|
|
{ //used as lvalue
|
|
the_item = rhs.the_item;
|
|
s.setItem(offset, the_item);
|
|
return *this;
|
|
}
|
|
|
|
seqref<T>& operator=(const T& ob)
|
|
{ // used as lvalue
|
|
the_item = ob;
|
|
s.setItem(offset, ob);
|
|
return *this;
|
|
}
|
|
|
|
// forward everything else to the item
|
|
PyObject* ptr () const
|
|
{
|
|
return the_item.ptr();
|
|
}
|
|
|
|
int reference_count () const
|
|
{ // the reference count
|
|
return the_item.reference_count();
|
|
}
|
|
|
|
Type type () const
|
|
{
|
|
return the_item.type();
|
|
}
|
|
|
|
String str () const;
|
|
|
|
String repr () const;
|
|
|
|
bool hasAttr (const std::string& attr_name) const
|
|
{
|
|
return the_item.hasAttr(attr_name);
|
|
}
|
|
|
|
Object getAttr (const std::string& attr_name) const
|
|
{
|
|
return the_item.getAttr(attr_name);
|
|
}
|
|
|
|
Object getItem (const Object& key) const
|
|
{
|
|
return the_item.getItem(key);
|
|
}
|
|
|
|
long hashValue () const
|
|
{
|
|
return the_item.hashValue();
|
|
}
|
|
|
|
bool isCallable () const
|
|
{
|
|
return the_item.isCallable();
|
|
}
|
|
|
|
bool isInstance () const
|
|
{
|
|
return the_item.isInstance();
|
|
}
|
|
|
|
bool isDict () const
|
|
{
|
|
return the_item.isDict();
|
|
}
|
|
|
|
bool isList () const
|
|
{
|
|
return the_item.isList();
|
|
}
|
|
|
|
bool isMapping () const
|
|
{
|
|
return the_item.isMapping();
|
|
}
|
|
|
|
bool isNumeric () const
|
|
{
|
|
return the_item.isNumeric();
|
|
}
|
|
|
|
bool isSequence () const
|
|
{
|
|
return the_item.isSequence();
|
|
}
|
|
|
|
bool isTrue () const
|
|
{
|
|
return the_item.isTrue();
|
|
}
|
|
|
|
bool isType (const Type& t) const
|
|
{
|
|
return the_item.isType (t);
|
|
}
|
|
|
|
bool isTuple() const
|
|
{
|
|
return the_item.isTuple();
|
|
}
|
|
|
|
bool isString() const
|
|
{
|
|
return the_item.isString();
|
|
}
|
|
// Commands
|
|
void setAttr (const std::string& attr_name, const Object& value)
|
|
{
|
|
the_item.setAttr(attr_name, value);
|
|
}
|
|
|
|
void delAttr (const std::string& attr_name)
|
|
{
|
|
the_item.delAttr(attr_name);
|
|
}
|
|
|
|
void delItem (const Object& key)
|
|
{
|
|
the_item.delItem(key);
|
|
}
|
|
|
|
bool operator==(const Object& o2) const
|
|
{
|
|
return the_item == o2;
|
|
}
|
|
|
|
bool operator!=(const Object& o2) const
|
|
{
|
|
return the_item != o2;
|
|
}
|
|
|
|
bool operator>=(const Object& o2) const
|
|
{
|
|
return the_item >= o2;
|
|
}
|
|
|
|
bool operator<=(const Object& o2) const
|
|
{
|
|
return the_item <= o2;
|
|
}
|
|
|
|
bool operator<(const Object& o2) const
|
|
{
|
|
return the_item < o2;
|
|
}
|
|
|
|
bool operator>(const Object& o2) const
|
|
{
|
|
return the_item > o2;
|
|
}
|
|
}; // end of seqref
|
|
|
|
|
|
// class SeqBase<T>
|
|
// ...the base class for all sequence types
|
|
|
|
template<typename T>
|
|
class SeqBase: public Object
|
|
{
|
|
public:
|
|
// STL definitions
|
|
typedef size_t size_type;
|
|
typedef seqref<T> reference;
|
|
typedef T const_reference;
|
|
typedef seqref<T>* pointer;
|
|
typedef int difference_type;
|
|
typedef T value_type; // TMM: 26Jun'01
|
|
|
|
virtual size_type max_size() const
|
|
{
|
|
return std::string::npos; // ?
|
|
}
|
|
|
|
virtual size_type capacity() const
|
|
{
|
|
return size();
|
|
}
|
|
|
|
virtual void swap(SeqBase<T>& c)
|
|
{
|
|
SeqBase<T> temp = c;
|
|
c = ptr();
|
|
set(temp.ptr());
|
|
}
|
|
|
|
virtual size_type size () const
|
|
{
|
|
return PySequence_Length (ptr());
|
|
}
|
|
|
|
explicit SeqBase<T> ()
|
|
:Object(PyTuple_New(0), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
explicit SeqBase<T> (PyObject* pyob, bool owned=false)
|
|
: Object(pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
SeqBase<T> (const Object& ob): Object(ob)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// Assignment acquires new ownership of pointer
|
|
|
|
SeqBase<T>& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
SeqBase<T>& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && PySequence_Check (pyob);
|
|
}
|
|
|
|
size_type length () const
|
|
{
|
|
return PySequence_Length (ptr());
|
|
}
|
|
|
|
// Element access
|
|
const T operator[](sequence_index_type index) const
|
|
{
|
|
return getItem(index);
|
|
}
|
|
|
|
seqref<T> operator[](sequence_index_type index)
|
|
{
|
|
return seqref<T>(*this, index);
|
|
}
|
|
|
|
virtual T getItem (sequence_index_type i) const
|
|
{
|
|
return T(asObject(PySequence_GetItem (ptr(), i)));
|
|
}
|
|
|
|
virtual void setItem (sequence_index_type i, const T& ob)
|
|
{
|
|
if (PySequence_SetItem (ptr(), i, *ob) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
SeqBase<T> repeat (int count) const
|
|
{
|
|
return SeqBase<T> (PySequence_Repeat (ptr(), count), true);
|
|
}
|
|
|
|
SeqBase<T> concat (const SeqBase<T>& other) const
|
|
{
|
|
return SeqBase<T> (PySequence_Concat(ptr(), *other), true);
|
|
}
|
|
|
|
// more STL compatability
|
|
const T front () const
|
|
{
|
|
return getItem(0);
|
|
}
|
|
|
|
seqref<T> front()
|
|
{
|
|
return seqref<T>(this, 0);
|
|
}
|
|
|
|
const T back () const
|
|
{
|
|
return getItem(size()-1);
|
|
}
|
|
|
|
seqref<T> back()
|
|
{
|
|
return seqref<T>(this, size()-1);
|
|
}
|
|
|
|
void verify_length(size_type required_size) const
|
|
{
|
|
if (size() != required_size)
|
|
throw IndexError ("Unexpected SeqBase<T> length.");
|
|
}
|
|
|
|
void verify_length(size_type min_size, size_type max_size) const
|
|
{
|
|
size_type n = size();
|
|
if (n < min_size || n > max_size)
|
|
throw IndexError ("Unexpected SeqBase<T> length.");
|
|
}
|
|
|
|
class iterator
|
|
: public random_access_iterator_parent(seqref<T>)
|
|
{
|
|
protected:
|
|
friend class SeqBase<T>;
|
|
SeqBase<T>* seq;
|
|
int count;
|
|
|
|
public:
|
|
~iterator ()
|
|
{}
|
|
|
|
iterator ()
|
|
: seq( 0 )
|
|
, count( 0 )
|
|
{}
|
|
|
|
iterator (SeqBase<T>* s, int where)
|
|
: seq( s )
|
|
, count( where )
|
|
{}
|
|
|
|
iterator (const iterator& other)
|
|
: seq( other.seq )
|
|
, count( other.count )
|
|
{}
|
|
|
|
bool eql (const iterator& other) const
|
|
{
|
|
return (*seq == *other.seq) && (count == other.count);
|
|
}
|
|
|
|
bool neq (const iterator& other) const
|
|
{
|
|
return (*seq != *other.seq) || (count != other.count);
|
|
}
|
|
|
|
bool lss (const iterator& other) const
|
|
{
|
|
return (count < other.count);
|
|
}
|
|
|
|
bool gtr (const iterator& other) const
|
|
{
|
|
return (count > other.count);
|
|
}
|
|
|
|
bool leq (const iterator& other) const
|
|
{
|
|
return (count <= other.count);
|
|
}
|
|
|
|
bool geq (const iterator& other) const
|
|
{
|
|
return (count >= other.count);
|
|
}
|
|
|
|
seqref<T> operator*()
|
|
{
|
|
return seqref<T>(*seq, count);
|
|
}
|
|
|
|
seqref<T> operator[] (sequence_index_type i)
|
|
{
|
|
return seqref<T>(*seq, count + i);
|
|
}
|
|
|
|
iterator& operator=(const iterator& other)
|
|
{
|
|
if (this == &other) return *this;
|
|
seq = other.seq;
|
|
count = other.count;
|
|
return *this;
|
|
}
|
|
|
|
iterator operator+(int n) const
|
|
{
|
|
return iterator(seq, count + n);
|
|
}
|
|
|
|
iterator operator-(int n) const
|
|
{
|
|
return iterator(seq, count - n);
|
|
}
|
|
|
|
iterator& operator+=(int n)
|
|
{
|
|
count = count + n;
|
|
return *this;
|
|
}
|
|
|
|
iterator& operator-=(int n)
|
|
{
|
|
count = count - n;
|
|
return *this;
|
|
}
|
|
|
|
int operator-(const iterator& other) const
|
|
{
|
|
if (*seq != *other.seq)
|
|
throw RuntimeError ("SeqBase<T>::iterator comparison error");
|
|
return count - other.count;
|
|
}
|
|
|
|
// prefix ++
|
|
iterator& operator++ ()
|
|
{ count++; return *this;}
|
|
// postfix ++
|
|
iterator operator++ (int)
|
|
{ return iterator(seq, count++);}
|
|
// prefix --
|
|
iterator& operator-- ()
|
|
{ count--; return *this;}
|
|
// postfix --
|
|
iterator operator-- (int)
|
|
{ return iterator(seq, count--);}
|
|
|
|
std::string diagnose() const
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "iterator diagnosis " << seq << ", " << count << std::ends;
|
|
return std::string(oss.str());
|
|
}
|
|
}; // end of class SeqBase<T>::iterator
|
|
|
|
iterator begin ()
|
|
{
|
|
return iterator(this, 0);
|
|
}
|
|
|
|
iterator end ()
|
|
{
|
|
return iterator(this, length());
|
|
}
|
|
|
|
class const_iterator
|
|
: public random_access_iterator_parent(const Object)
|
|
{
|
|
protected:
|
|
friend class SeqBase<T>;
|
|
const SeqBase<T>* seq;
|
|
sequence_index_type count;
|
|
|
|
public:
|
|
~const_iterator ()
|
|
{}
|
|
|
|
const_iterator ()
|
|
: seq( 0 )
|
|
, count( 0 )
|
|
{}
|
|
|
|
const_iterator (const SeqBase<T>* s, int where)
|
|
: seq( s )
|
|
, count( where )
|
|
{}
|
|
|
|
const_iterator(const const_iterator& other)
|
|
: seq( other.seq )
|
|
, count( other.count )
|
|
{}
|
|
|
|
const T operator*() const
|
|
{
|
|
return seq->getItem(count);
|
|
}
|
|
|
|
const T operator[] (sequence_index_type i) const
|
|
{
|
|
return seq->getItem(count + i);
|
|
}
|
|
|
|
const_iterator& operator=(const const_iterator& other)
|
|
{
|
|
if (this == &other) return *this;
|
|
seq = other.seq;
|
|
count = other.count;
|
|
return *this;
|
|
}
|
|
|
|
const_iterator operator+(int n) const
|
|
{
|
|
return const_iterator(seq, count + n);
|
|
}
|
|
|
|
bool eql (const const_iterator& other) const
|
|
{
|
|
return (*seq == *other.seq) && (count == other.count);
|
|
}
|
|
|
|
bool neq (const const_iterator& other) const
|
|
{
|
|
return (*seq != *other.seq) || (count != other.count);
|
|
}
|
|
|
|
bool lss (const const_iterator& other) const
|
|
{
|
|
return (count < other.count);
|
|
}
|
|
|
|
bool gtr (const const_iterator& other) const
|
|
{
|
|
return (count > other.count);
|
|
}
|
|
|
|
bool leq (const const_iterator& other) const
|
|
{
|
|
return (count <= other.count);
|
|
}
|
|
|
|
bool geq (const const_iterator& other) const
|
|
{
|
|
return (count >= other.count);
|
|
}
|
|
|
|
const_iterator operator-(int n)
|
|
{
|
|
return const_iterator(seq, count - n);
|
|
}
|
|
|
|
const_iterator& operator+=(int n)
|
|
{
|
|
count = count + n;
|
|
return *this;
|
|
}
|
|
|
|
const_iterator& operator-=(int n)
|
|
{
|
|
count = count - n;
|
|
return *this;
|
|
}
|
|
|
|
int operator-(const const_iterator& other) const
|
|
{
|
|
if (*seq != *other.seq)
|
|
throw RuntimeError ("SeqBase<T>::const_iterator::- error");
|
|
return count - other.count;
|
|
}
|
|
// prefix ++
|
|
const_iterator& operator++ ()
|
|
{ count++; return *this;}
|
|
// postfix ++
|
|
const_iterator operator++ (int)
|
|
{ return const_iterator(seq, count++);}
|
|
// prefix --
|
|
const_iterator& operator-- ()
|
|
{ count--; return *this;}
|
|
// postfix --
|
|
const_iterator operator-- (int)
|
|
{ return const_iterator(seq, count--);}
|
|
}; // end of class SeqBase<T>::const_iterator
|
|
|
|
const_iterator begin () const
|
|
{
|
|
return const_iterator(this, 0);
|
|
}
|
|
|
|
const_iterator end () const
|
|
{
|
|
return const_iterator(this, length());
|
|
}
|
|
};
|
|
|
|
// Here's an important typedef you might miss if reading too fast...
|
|
typedef SeqBase<Object> Sequence;
|
|
|
|
template <typename T> bool operator==(const typename SeqBase<T>::iterator& left, const typename SeqBase<T>::iterator& right);
|
|
template <typename T> bool operator!=(const typename SeqBase<T>::iterator& left, const typename SeqBase<T>::iterator& right);
|
|
template <typename T> bool operator< (const typename SeqBase<T>::iterator& left, const typename SeqBase<T>::iterator& right);
|
|
template <typename T> bool operator> (const typename SeqBase<T>::iterator& left, const typename SeqBase<T>::iterator& right);
|
|
template <typename T> bool operator<=(const typename SeqBase<T>::iterator& left, const typename SeqBase<T>::iterator& right);
|
|
template <typename T> bool operator>=(const typename SeqBase<T>::iterator& left, const typename SeqBase<T>::iterator& right);
|
|
|
|
template <typename T> bool operator==(const typename SeqBase<T>::const_iterator& left, const typename SeqBase<T>::const_iterator& right);
|
|
template <typename T> bool operator!=(const typename SeqBase<T>::const_iterator& left, const typename SeqBase<T>::const_iterator& right);
|
|
template <typename T> bool operator< (const typename SeqBase<T>::const_iterator& left, const typename SeqBase<T>::const_iterator& right);
|
|
template <typename T> bool operator> (const typename SeqBase<T>::const_iterator& left, const typename SeqBase<T>::const_iterator& right);
|
|
template <typename T> bool operator<=(const typename SeqBase<T>::const_iterator& left, const typename SeqBase<T>::const_iterator& right);
|
|
template <typename T> bool operator>=(const typename SeqBase<T>::const_iterator& left, const typename SeqBase<T>::const_iterator& right);
|
|
|
|
|
|
extern bool operator==(const Sequence::iterator& left, const Sequence::iterator& right);
|
|
extern bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right);
|
|
extern bool operator< (const Sequence::iterator& left, const Sequence::iterator& right);
|
|
extern bool operator> (const Sequence::iterator& left, const Sequence::iterator& right);
|
|
extern bool operator<=(const Sequence::iterator& left, const Sequence::iterator& right);
|
|
extern bool operator>=(const Sequence::iterator& left, const Sequence::iterator& right);
|
|
|
|
extern bool operator==(const Sequence::const_iterator& left, const Sequence::const_iterator& right);
|
|
extern bool operator!=(const Sequence::const_iterator& left, const Sequence::const_iterator& right);
|
|
extern bool operator< (const Sequence::const_iterator& left, const Sequence::const_iterator& right);
|
|
extern bool operator> (const Sequence::const_iterator& left, const Sequence::const_iterator& right);
|
|
extern bool operator<=(const Sequence::const_iterator& left, const Sequence::const_iterator& right);
|
|
extern bool operator>=(const Sequence::const_iterator& left, const Sequence::const_iterator& right);
|
|
|
|
// ==================================================
|
|
// class Char
|
|
// Python strings return strings as individual elements.
|
|
// I'll try having a class Char which is a String of length 1
|
|
//
|
|
typedef std::basic_string<Py_UNICODE> unicodestring;
|
|
extern Py_UNICODE unicode_null_string[1];
|
|
|
|
class Char: public Object
|
|
{
|
|
public:
|
|
explicit Char (PyObject *pyob, bool owned = false): Object(pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Char (const Object& ob): Object(ob)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Char (const std::string& v = "")
|
|
:Object(PyString_FromStringAndSize (const_cast<char*>(v.c_str()),1), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Char (char v)
|
|
: Object(PyString_FromStringAndSize (&v, 1), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Char (Py_UNICODE v)
|
|
: Object(PyUnicode_FromUnicode (&v, 1), true)
|
|
{
|
|
validate();
|
|
}
|
|
// Assignment acquires new ownership of pointer
|
|
Char& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Char& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob)) && PySequence_Length (pyob) == 1;
|
|
}
|
|
|
|
// Assignment from C string
|
|
Char& operator= (const std::string& v)
|
|
{
|
|
set(PyString_FromStringAndSize (const_cast<char*>(v.c_str()),1), true);
|
|
return *this;
|
|
}
|
|
|
|
Char& operator= (char v)
|
|
{
|
|
set(PyString_FromStringAndSize (&v, 1), true);
|
|
return *this;
|
|
}
|
|
|
|
Char& operator= (const unicodestring& v)
|
|
{
|
|
set(PyUnicode_FromUnicode (const_cast<Py_UNICODE*>(v.data()),1), true);
|
|
return *this;
|
|
}
|
|
|
|
Char& operator= (Py_UNICODE v)
|
|
{
|
|
set(PyUnicode_FromUnicode (&v, 1), true);
|
|
return *this;
|
|
}
|
|
|
|
// Conversion
|
|
operator String() const;
|
|
|
|
operator std::string () const
|
|
{
|
|
return std::string(PyString_AsString (ptr()));
|
|
}
|
|
};
|
|
|
|
class String: public SeqBase<Char>
|
|
{
|
|
public:
|
|
virtual size_type capacity() const
|
|
{
|
|
return max_size();
|
|
}
|
|
|
|
explicit String (PyObject *pyob, bool owned = false): SeqBase<Char>(pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
String (const Object& ob): SeqBase<Char>(ob)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
String()
|
|
: SeqBase<Char>( PyString_FromStringAndSize( "", 0 ), true )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
String( const std::string& v )
|
|
: SeqBase<Char>( PyString_FromStringAndSize( const_cast<char*>(v.data()),
|
|
static_cast<int>( v.length() ) ), true )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
String( const char *s, const char *encoding, const char *error="strict" )
|
|
: SeqBase<Char>( PyUnicode_Decode( s, strlen( s ), encoding, error ), true )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
String( const char *s, int len, const char *encoding, const char *error="strict" )
|
|
: SeqBase<Char>( PyUnicode_Decode( s, len, encoding, error ), true )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
String( const std::string &s, const char *encoding, const char *error="strict" )
|
|
: SeqBase<Char>( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
String( const std::string& v, std::string::size_type vsize )
|
|
: SeqBase<Char>(PyString_FromStringAndSize( const_cast<char*>(v.data()),
|
|
static_cast<int>( vsize ) ), true)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
String( const char *v, int vsize )
|
|
: SeqBase<Char>(PyString_FromStringAndSize( const_cast<char*>(v), vsize ), true )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
String( const char* v )
|
|
: SeqBase<Char>( PyString_FromString( v ), true )
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// Assignment acquires new ownership of pointer
|
|
String& operator= ( const Object& rhs )
|
|
{
|
|
return *this = *rhs;
|
|
}
|
|
|
|
String& operator= (PyObject* rhsp)
|
|
{
|
|
if( ptr() == rhsp )
|
|
return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob));
|
|
}
|
|
|
|
// Assignment from C string
|
|
String& operator= (const std::string& v)
|
|
{
|
|
set( PyString_FromStringAndSize( const_cast<char*>( v.data() ),
|
|
static_cast<int>( v.length() ) ), true );
|
|
return *this;
|
|
}
|
|
String& operator= (const unicodestring& v)
|
|
{
|
|
set( PyUnicode_FromUnicode( const_cast<Py_UNICODE*>( v.data() ),
|
|
static_cast<int>( v.length() ) ), true );
|
|
return *this;
|
|
}
|
|
|
|
|
|
// Encode
|
|
String encode( const char *encoding, const char *error="strict" )
|
|
{
|
|
if( isUnicode() )
|
|
{
|
|
return String( PyUnicode_AsEncodedString( ptr(), encoding, error ) );
|
|
}
|
|
else
|
|
{
|
|
return String( PyString_AsEncodedObject( ptr(), encoding, error ) );
|
|
}
|
|
}
|
|
|
|
String decode( const char *encoding, const char *error="strict" )
|
|
{
|
|
return Object( PyString_AsDecodedObject( ptr(), encoding, error ) );
|
|
}
|
|
|
|
// Queries
|
|
virtual size_type size () const
|
|
{
|
|
if( isUnicode() )
|
|
{
|
|
return static_cast<size_type>( PyUnicode_GET_SIZE (ptr()) );
|
|
}
|
|
else
|
|
{
|
|
return static_cast<size_type>( PyString_Size (ptr()) );
|
|
}
|
|
}
|
|
|
|
operator std::string () const
|
|
{
|
|
return as_std_string();
|
|
}
|
|
|
|
std::string as_std_string() const
|
|
{
|
|
if( isUnicode() )
|
|
{
|
|
throw TypeError("cannot return std::string from Unicode object");
|
|
}
|
|
else
|
|
{
|
|
return std::string( PyString_AsString( ptr() ), static_cast<size_type>( PyString_Size( ptr() ) ) );
|
|
}
|
|
}
|
|
|
|
unicodestring as_unicodestring() const
|
|
{
|
|
if( isUnicode() )
|
|
{
|
|
return unicodestring( PyUnicode_AS_UNICODE( ptr() ),
|
|
static_cast<size_type>( PyUnicode_GET_SIZE( ptr() ) ) );
|
|
}
|
|
else
|
|
{
|
|
throw TypeError("can only return unicodestring from Unicode object");
|
|
}
|
|
}
|
|
};
|
|
|
|
// ==================================================
|
|
// class Tuple
|
|
class Tuple: public Sequence
|
|
{
|
|
public:
|
|
virtual void setItem (sequence_index_type offset, const Object&ob)
|
|
{
|
|
// note PyTuple_SetItem is a thief...
|
|
if(PyTuple_SetItem (ptr(), offset, new_reference_to(ob)) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
// Constructor
|
|
explicit Tuple (PyObject *pyob, bool owned = false): Sequence (pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Tuple (const Object& ob): Sequence(ob)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// New tuple of a given size
|
|
explicit Tuple (int size = 0)
|
|
{
|
|
set(PyTuple_New (size), true);
|
|
validate ();
|
|
for (sequence_index_type i=0; i < size; i++)
|
|
{
|
|
if(PyTuple_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
}
|
|
// Tuple from any sequence
|
|
explicit Tuple (const Sequence& s)
|
|
{
|
|
sequence_index_type limit( sequence_index_type( s.length() ) );
|
|
|
|
set(PyTuple_New (limit), true);
|
|
validate();
|
|
|
|
for(sequence_index_type i=0; i < limit; i++)
|
|
{
|
|
if(PyTuple_SetItem (ptr(), i, new_reference_to(s[i])) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
}
|
|
// Assignment acquires new ownership of pointer
|
|
|
|
Tuple& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Tuple& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && Py::_Tuple_Check (pyob);
|
|
}
|
|
|
|
Tuple getSlice (int i, int j) const
|
|
{
|
|
return Tuple (PySequence_GetSlice (ptr(), i, j), true);
|
|
}
|
|
|
|
};
|
|
|
|
// ==================================================
|
|
// class List
|
|
|
|
class List: public Sequence
|
|
{
|
|
public:
|
|
// Constructor
|
|
explicit List (PyObject *pyob, bool owned = false): Sequence(pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
List (const Object& ob): Sequence(ob)
|
|
{
|
|
validate();
|
|
}
|
|
// Creation at a fixed size
|
|
List (int size = 0)
|
|
{
|
|
set(PyList_New (size), true);
|
|
validate();
|
|
for (sequence_index_type i=0; i < size; i++)
|
|
{
|
|
if(PyList_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
}
|
|
|
|
// List from a sequence
|
|
List (const Sequence& s): Sequence()
|
|
{
|
|
int n = s.length();
|
|
set(PyList_New (n), true);
|
|
validate();
|
|
for (sequence_index_type i=0; i < n; i++)
|
|
{
|
|
if(PyList_SetItem (ptr(), i, new_reference_to(s[i])) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual size_type capacity() const
|
|
{
|
|
return max_size();
|
|
}
|
|
// Assignment acquires new ownership of pointer
|
|
|
|
List& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
List& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && Py::_List_Check (pyob);
|
|
}
|
|
|
|
List getSlice (int i, int j) const
|
|
{
|
|
return List (PyList_GetSlice (ptr(), i, j), true);
|
|
}
|
|
|
|
void setSlice (int i, int j, const Object& v)
|
|
{
|
|
if(PyList_SetSlice (ptr(), i, j, *v) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
void append (const Object& ob)
|
|
{
|
|
if(PyList_Append (ptr(), *ob) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
void insert (int i, const Object& ob)
|
|
{
|
|
if(PyList_Insert (ptr(), i, *ob) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
void sort ()
|
|
{
|
|
if(PyList_Sort(ptr()) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
void reverse ()
|
|
{
|
|
if(PyList_Reverse(ptr()) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
// Mappings
|
|
// ==================================================
|
|
template<typename T>
|
|
class mapref
|
|
{
|
|
protected:
|
|
MapBase<T>& s; // the map
|
|
Object key; // item key
|
|
T the_item;
|
|
|
|
public:
|
|
mapref<T> (MapBase<T>& map, const std::string& k)
|
|
: s(map), the_item()
|
|
{
|
|
key = String(k);
|
|
if(map.hasKey(key)) the_item = map.getItem(key);
|
|
};
|
|
|
|
mapref<T> (MapBase<T>& map, const Object& k)
|
|
: s(map), key(k), the_item()
|
|
{
|
|
if(map.hasKey(key)) the_item = map.getItem(key);
|
|
};
|
|
|
|
~mapref()
|
|
{}
|
|
|
|
// MapBase<T> stuff
|
|
// lvalue
|
|
mapref<T>& operator=(const mapref<T>& other)
|
|
{
|
|
if(this == &other) return *this;
|
|
the_item = other.the_item;
|
|
s.setItem(key, other.the_item);
|
|
return *this;
|
|
};
|
|
|
|
mapref<T>& operator= (const T& ob)
|
|
{
|
|
the_item = ob;
|
|
s.setItem (key, ob);
|
|
return *this;
|
|
}
|
|
|
|
// rvalue
|
|
operator T() const
|
|
{
|
|
return the_item;
|
|
}
|
|
|
|
// forward everything else to the_item
|
|
PyObject* ptr () const
|
|
{
|
|
return the_item.ptr();
|
|
}
|
|
|
|
int reference_count () const
|
|
{ // the mapref count
|
|
return the_item.reference_count();
|
|
}
|
|
|
|
Type type () const
|
|
{
|
|
return the_item.type();
|
|
}
|
|
|
|
String str () const
|
|
{
|
|
return the_item.str();
|
|
}
|
|
|
|
String repr () const
|
|
{
|
|
return the_item.repr();
|
|
}
|
|
|
|
bool hasAttr (const std::string& attr_name) const
|
|
{
|
|
return the_item.hasAttr(attr_name);
|
|
}
|
|
|
|
Object getAttr (const std::string& attr_name) const
|
|
{
|
|
return the_item.getAttr(attr_name);
|
|
}
|
|
|
|
Object getItem (const Object& k) const
|
|
{
|
|
return the_item.getItem(k);
|
|
}
|
|
|
|
long hashValue () const
|
|
{
|
|
return the_item.hashValue();
|
|
}
|
|
|
|
bool isCallable () const
|
|
{
|
|
return the_item.isCallable();
|
|
}
|
|
|
|
bool isList () const
|
|
{
|
|
return the_item.isList();
|
|
}
|
|
|
|
bool isMapping () const
|
|
{
|
|
return the_item.isMapping();
|
|
}
|
|
|
|
bool isNumeric () const
|
|
{
|
|
return the_item.isNumeric();
|
|
}
|
|
|
|
bool isSequence () const
|
|
{
|
|
return the_item.isSequence();
|
|
}
|
|
|
|
bool isTrue () const
|
|
{
|
|
return the_item.isTrue();
|
|
}
|
|
|
|
bool isType (const Type& t) const
|
|
{
|
|
return the_item.isType (t);
|
|
}
|
|
|
|
bool isTuple() const
|
|
{
|
|
return the_item.isTuple();
|
|
}
|
|
|
|
bool isString() const
|
|
{
|
|
return the_item.isString();
|
|
}
|
|
|
|
// Commands
|
|
void setAttr (const std::string& attr_name, const Object& value)
|
|
{
|
|
the_item.setAttr(attr_name, value);
|
|
}
|
|
|
|
void delAttr (const std::string& attr_name)
|
|
{
|
|
the_item.delAttr(attr_name);
|
|
}
|
|
|
|
void delItem (const Object& k)
|
|
{
|
|
the_item.delItem(k);
|
|
}
|
|
}; // end of mapref
|
|
|
|
// TMM: now for mapref<T>
|
|
template< class T >
|
|
bool operator==(const mapref<T>& left, const mapref<T>& right)
|
|
{
|
|
return true; // NOT completed.
|
|
}
|
|
|
|
template< class T >
|
|
bool operator!=(const mapref<T>& left, const mapref<T>& right)
|
|
{
|
|
return true; // not completed.
|
|
}
|
|
|
|
template<typename T>
|
|
class MapBase: public Object
|
|
{
|
|
protected:
|
|
explicit MapBase<T>()
|
|
{}
|
|
public:
|
|
// reference: proxy class for implementing []
|
|
// TMM: 26Jun'01 - the types
|
|
// If you assume that Python mapping is a hash_map...
|
|
// hash_map::value_type is not assignable, but
|
|
// (*it).second = data must be a valid expression
|
|
typedef size_t size_type;
|
|
typedef Object key_type;
|
|
typedef mapref<T> data_type;
|
|
typedef std::pair< const T, T > value_type;
|
|
typedef std::pair< const T, mapref<T> > reference;
|
|
typedef const std::pair< const T, const T > const_reference;
|
|
typedef std::pair< const T, mapref<T> > pointer;
|
|
|
|
// Constructor
|
|
explicit MapBase<T> (PyObject *pyob, bool owned = false): Object(pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// TMM: 02Jul'01 - changed MapBase<T> to Object in next line
|
|
MapBase<T> (const Object& ob): Object(ob)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// Assignment acquires new ownership of pointer
|
|
MapBase<T>& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
MapBase<T>& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && PyMapping_Check(pyob);
|
|
}
|
|
|
|
// Clear -- PyMapping Clear is missing
|
|
//
|
|
|
|
void clear ()
|
|
{
|
|
List k = keys();
|
|
for(List::iterator i = k.begin(); i != k.end(); i++)
|
|
{
|
|
delItem(*i);
|
|
}
|
|
}
|
|
|
|
virtual size_type size() const
|
|
{
|
|
return PyMapping_Length (ptr());
|
|
}
|
|
|
|
// Element Access
|
|
T operator[](const std::string& key) const
|
|
{
|
|
return getItem(key);
|
|
}
|
|
|
|
T operator[](const Object& key) const
|
|
{
|
|
return getItem(key);
|
|
}
|
|
|
|
mapref<T> operator[](const std::string& key)
|
|
{
|
|
return mapref<T>(*this, key);
|
|
}
|
|
|
|
mapref<T> operator[](const Object& key)
|
|
{
|
|
return mapref<T>(*this, key);
|
|
}
|
|
|
|
int length () const
|
|
{
|
|
return PyMapping_Length (ptr());
|
|
}
|
|
|
|
bool hasKey (const std::string& s) const
|
|
{
|
|
return PyMapping_HasKeyString (ptr(),const_cast<char*>(s.c_str())) != 0;
|
|
}
|
|
|
|
bool hasKey (const Object& s) const
|
|
{
|
|
return PyMapping_HasKey (ptr(), s.ptr()) != 0;
|
|
}
|
|
|
|
T getItem (const std::string& s) const
|
|
{
|
|
return T(
|
|
asObject(PyMapping_GetItemString (ptr(),const_cast<char*>(s.c_str())))
|
|
);
|
|
}
|
|
|
|
T getItem (const Object& s) const
|
|
{
|
|
return T(
|
|
asObject(PyObject_GetItem (ptr(), s.ptr()))
|
|
);
|
|
}
|
|
|
|
virtual void setItem (const char *s, const Object& ob)
|
|
{
|
|
if (PyMapping_SetItemString (ptr(), const_cast<char*>(s), *ob) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
virtual void setItem (const std::string& s, const Object& ob)
|
|
{
|
|
if (PyMapping_SetItemString (ptr(), const_cast<char*>(s.c_str()), *ob) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
virtual void setItem (const Object& s, const Object& ob)
|
|
{
|
|
if (PyObject_SetItem (ptr(), s.ptr(), ob.ptr()) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
void delItem (const std::string& s)
|
|
{
|
|
if (PyMapping_DelItemString (ptr(), const_cast<char*>(s.c_str())) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
|
|
void delItem (const Object& s)
|
|
{
|
|
if (PyMapping_DelItem (ptr(), *s) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
}
|
|
// Queries
|
|
List keys () const
|
|
{
|
|
return List(PyMapping_Keys(ptr()), true);
|
|
}
|
|
|
|
List values () const
|
|
{ // each returned item is a (key, value) pair
|
|
return List(PyMapping_Values(ptr()), true);
|
|
}
|
|
|
|
List items () const
|
|
{
|
|
return List(PyMapping_Items(ptr()), true);
|
|
}
|
|
|
|
// iterators for MapBase<T>
|
|
// Added by TMM: 2Jul'01 - NOT COMPLETED
|
|
// There is still a bug. I decided to stop, before fixing the bug, because
|
|
// this can't be halfway efficient until Python gets built-in iterators.
|
|
// My current soln is to iterate over the map by getting a copy of its keys
|
|
// and iterating over that. Not a good solution.
|
|
|
|
// The iterator holds a MapBase<T>* rather than a MapBase<T> because that's
|
|
// how the sequence iterator is implemented and it works. But it does seem
|
|
// odd to me - we are iterating over the map object, not the reference.
|
|
|
|
#if 0 // here is the test code with which I found the (still existing) bug
|
|
typedef cxx::Dict d_t;
|
|
d_t d;
|
|
cxx::String s1("blah");
|
|
cxx::String s2("gorf");
|
|
d[ "one" ] = s1;
|
|
d[ "two" ] = s1;
|
|
d[ "three" ] = s2;
|
|
d[ "four" ] = s2;
|
|
|
|
d_t::iterator it;
|
|
it = d.begin(); // this (using the assignment operator) is causing
|
|
// a problem; if I just use the copy ctor it works fine.
|
|
for( ; it != d.end(); ++it )
|
|
{
|
|
d_t::value_type vt( *it );
|
|
cxx::String rs = vt.second.repr();
|
|
std::string ls = rs.operator std::string();
|
|
fprintf( stderr, "%s\n", ls );
|
|
}
|
|
#endif // 0
|
|
|
|
class iterator
|
|
{
|
|
// : public forward_iterator_parent( std::pair<const T,T> ) {
|
|
protected:
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
typedef std::pair< const T, T > value_type;
|
|
typedef int difference_type;
|
|
typedef std::pair< const T, mapref<T> > pointer;
|
|
typedef std::pair< const T, mapref<T> > reference;
|
|
|
|
friend class MapBase<T>;
|
|
//
|
|
MapBase<T>* map;
|
|
List keys; // for iterating over the map
|
|
List::iterator pos; // index into the keys
|
|
|
|
public:
|
|
~iterator ()
|
|
{}
|
|
|
|
iterator ()
|
|
: map( 0 )
|
|
, keys()
|
|
, pos()
|
|
{}
|
|
|
|
iterator (MapBase<T>* m, bool end = false )
|
|
: map( m )
|
|
, keys( m->keys() )
|
|
, pos( end ? keys.end() : keys.begin() )
|
|
{}
|
|
|
|
iterator (const iterator& other)
|
|
: map( other.map )
|
|
, keys( other.keys )
|
|
, pos( other.pos )
|
|
{}
|
|
|
|
reference operator*()
|
|
{
|
|
Object key = *pos;
|
|
return std::make_pair(key, mapref<T>(*map,key));
|
|
}
|
|
|
|
iterator& operator=(const iterator& other)
|
|
{
|
|
if (this == &other)
|
|
return *this;
|
|
map = other.map;
|
|
keys = other.keys;
|
|
pos = other.pos;
|
|
return *this;
|
|
}
|
|
|
|
bool eql(const iterator& right) const
|
|
{
|
|
return *map == *right.map && pos == right.pos;
|
|
}
|
|
bool neq( const iterator& right ) const
|
|
{
|
|
return *map != *right.map || pos != right.pos;
|
|
}
|
|
|
|
// pointer operator->() {
|
|
// return ;
|
|
// }
|
|
|
|
// prefix ++
|
|
iterator& operator++ ()
|
|
{ pos++; return *this;}
|
|
// postfix ++
|
|
iterator operator++ (int)
|
|
{ return iterator(map, keys, pos++);}
|
|
// prefix --
|
|
iterator& operator-- ()
|
|
{ pos--; return *this;}
|
|
// postfix --
|
|
iterator operator-- (int)
|
|
{ return iterator(map, keys, pos--);}
|
|
|
|
std::string diagnose() const
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "iterator diagnosis " << map << ", " << pos << std::ends;
|
|
return std::string(oss.str());
|
|
}
|
|
}; // end of class MapBase<T>::iterator
|
|
|
|
iterator begin ()
|
|
{
|
|
return iterator(this);
|
|
}
|
|
|
|
iterator end ()
|
|
{
|
|
return iterator(this, true);
|
|
}
|
|
|
|
class const_iterator
|
|
{
|
|
protected:
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
typedef const std::pair< const T, T > value_type;
|
|
typedef int difference_type;
|
|
typedef const std::pair< const T, T > pointer;
|
|
typedef const std::pair< const T, T > reference;
|
|
|
|
friend class MapBase<T>;
|
|
const MapBase<T>* map;
|
|
List keys; // for iterating over the map
|
|
List::iterator pos; // index into the keys
|
|
|
|
public:
|
|
~const_iterator ()
|
|
{}
|
|
|
|
const_iterator ()
|
|
: map( 0 )
|
|
, keys()
|
|
, pos()
|
|
{}
|
|
|
|
const_iterator (const MapBase<T>* m, List k, List::iterator p )
|
|
: map( m )
|
|
, keys( k )
|
|
, pos( p )
|
|
{}
|
|
|
|
const_iterator(const const_iterator& other)
|
|
: map( other.map )
|
|
, keys( other.keys )
|
|
, pos( other.pos )
|
|
{}
|
|
|
|
bool eql(const const_iterator& right) const
|
|
{
|
|
return *map == *right.map && pos == right.pos;
|
|
}
|
|
bool neq( const const_iterator& right ) const
|
|
{
|
|
return *map != *right.map || pos != right.pos;
|
|
}
|
|
|
|
|
|
// const_reference operator*() {
|
|
// Object key = *pos;
|
|
// return std::make_pair( key, map->[key] );
|
|
// GCC < 3 barfes on this line at the '['.
|
|
// }
|
|
|
|
const_iterator& operator=(const const_iterator& other)
|
|
{
|
|
if (this == &other) return *this;
|
|
map = other.map;
|
|
keys = other.keys;
|
|
pos = other.pos;
|
|
return *this;
|
|
}
|
|
|
|
// prefix ++
|
|
const_iterator& operator++ ()
|
|
{ pos++; return *this;}
|
|
// postfix ++
|
|
const_iterator operator++ (int)
|
|
{ return const_iterator(map, keys, pos++);}
|
|
// prefix --
|
|
const_iterator& operator-- ()
|
|
{ pos--; return *this;}
|
|
// postfix --
|
|
const_iterator operator-- (int)
|
|
{ return const_iterator(map, keys, pos--);}
|
|
}; // end of class MapBase<T>::const_iterator
|
|
|
|
const_iterator begin () const
|
|
{
|
|
return const_iterator(this, 0);
|
|
}
|
|
|
|
const_iterator end () const
|
|
{
|
|
return const_iterator(this, length());
|
|
}
|
|
|
|
}; // end of MapBase<T>
|
|
|
|
typedef MapBase<Object> Mapping;
|
|
|
|
template <typename T> bool operator==(const typename MapBase<T>::iterator& left, const typename MapBase<T>::iterator& right);
|
|
template <typename T> bool operator!=(const typename MapBase<T>::iterator& left, const typename MapBase<T>::iterator& right);
|
|
template <typename T> bool operator==(const typename MapBase<T>::const_iterator& left, const typename MapBase<T>::const_iterator& right);
|
|
template <typename T> bool operator!=(const typename MapBase<T>::const_iterator& left, const typename MapBase<T>::const_iterator& right);
|
|
|
|
extern bool operator==(const Mapping::iterator& left, const Mapping::iterator& right);
|
|
extern bool operator!=(const Mapping::iterator& left, const Mapping::iterator& right);
|
|
extern bool operator==(const Mapping::const_iterator& left, const Mapping::const_iterator& right);
|
|
extern bool operator!=(const Mapping::const_iterator& left, const Mapping::const_iterator& right);
|
|
|
|
|
|
// ==================================================
|
|
// class Dict
|
|
class Dict: public Mapping
|
|
{
|
|
public:
|
|
// Constructor
|
|
explicit Dict (PyObject *pyob, bool owned=false): Mapping (pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
Dict (const Dict& ob): Mapping(ob)
|
|
{
|
|
validate();
|
|
}
|
|
// Creation
|
|
Dict ()
|
|
{
|
|
set(PyDict_New (), true);
|
|
validate();
|
|
}
|
|
// Assignment acquires new ownership of pointer
|
|
|
|
Dict& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Dict& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set(rhsp);
|
|
return *this;
|
|
}
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && Py::_Dict_Check (pyob);
|
|
}
|
|
};
|
|
|
|
class Callable: public Object
|
|
{
|
|
protected:
|
|
explicit Callable (): Object()
|
|
{}
|
|
public:
|
|
// Constructor
|
|
explicit Callable (PyObject *pyob, bool owned = false): Object (pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Callable (const Object& ob): Object(ob)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// Assignment acquires new ownership of pointer
|
|
|
|
Callable& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Callable& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set (rhsp);
|
|
return *this;
|
|
}
|
|
|
|
// Membership
|
|
virtual bool accepts (PyObject *pyob) const
|
|
{
|
|
return pyob && PyCallable_Check (pyob);
|
|
}
|
|
|
|
// Call
|
|
Object apply(const Tuple& args) const
|
|
{
|
|
return asObject(PyObject_CallObject(ptr(), args.ptr()));
|
|
}
|
|
|
|
// Call with keywords
|
|
Object apply(const Tuple& args, const Dict& kw) const
|
|
{
|
|
return asObject( PyEval_CallObjectWithKeywords( ptr(), args.ptr(), kw.ptr() ) );
|
|
}
|
|
|
|
Object apply(PyObject* pargs = 0) const
|
|
{
|
|
return apply (Tuple(pargs));
|
|
}
|
|
};
|
|
|
|
class Module: public Object
|
|
{
|
|
public:
|
|
explicit Module (PyObject* pyob, bool owned = false): Object (pyob, owned)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
// Construct from module name
|
|
explicit Module (const std::string&s): Object()
|
|
{
|
|
PyObject *m = PyImport_AddModule( const_cast<char *>(s.c_str()) );
|
|
set( m, false );
|
|
validate ();
|
|
}
|
|
|
|
// Copy constructor acquires new ownership of pointer
|
|
Module (const Module& ob): Object(*ob)
|
|
{
|
|
validate();
|
|
}
|
|
|
|
Module& operator= (const Object& rhs)
|
|
{
|
|
return (*this = *rhs);
|
|
}
|
|
|
|
Module& operator= (PyObject* rhsp)
|
|
{
|
|
if(ptr() == rhsp) return *this;
|
|
set(rhsp);
|
|
return *this;
|
|
}
|
|
|
|
Dict getDict()
|
|
{
|
|
return Dict(PyModule_GetDict(ptr()));
|
|
// Caution -- PyModule_GetDict returns borrowed reference!
|
|
}
|
|
};
|
|
|
|
// Numeric interface
|
|
inline Object operator+ (const Object& a)
|
|
{
|
|
return asObject(PyNumber_Positive(*a));
|
|
}
|
|
inline Object operator- (const Object& a)
|
|
{
|
|
return asObject(PyNumber_Negative(*a));
|
|
}
|
|
|
|
inline Object abs(const Object& a)
|
|
{
|
|
return asObject(PyNumber_Absolute(*a));
|
|
}
|
|
|
|
inline std::pair<Object,Object> coerce(const Object& a, const Object& b)
|
|
{
|
|
PyObject *p1, *p2;
|
|
p1 = *a;
|
|
p2 = *b;
|
|
if(PyNumber_Coerce(&p1,&p2) == -1)
|
|
{
|
|
throw Exception();
|
|
}
|
|
return std::pair<Object,Object>(asObject(p1), asObject(p2));
|
|
}
|
|
|
|
inline Object operator+ (const Object& a, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Add(*a, *b));
|
|
}
|
|
inline Object operator+ (const Object& a, int j)
|
|
{
|
|
return asObject(PyNumber_Add(*a, *Int(j)));
|
|
}
|
|
inline Object operator+ (const Object& a, double v)
|
|
{
|
|
return asObject(PyNumber_Add(*a, *Float(v)));
|
|
}
|
|
inline Object operator+ (int j, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Add(*Int(j), *b));
|
|
}
|
|
inline Object operator+ (double v, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Add(*Float(v), *b));
|
|
}
|
|
|
|
inline Object operator- (const Object& a, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Subtract(*a, *b));
|
|
}
|
|
inline Object operator- (const Object& a, int j)
|
|
{
|
|
return asObject(PyNumber_Subtract(*a, *Int(j)));
|
|
}
|
|
inline Object operator- (const Object& a, double v)
|
|
{
|
|
return asObject(PyNumber_Subtract(*a, *Float(v)));
|
|
}
|
|
inline Object operator- (int j, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Subtract(*Int(j), *b));
|
|
}
|
|
inline Object operator- (double v, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Subtract(*Float(v), *b));
|
|
}
|
|
|
|
inline Object operator* (const Object& a, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Multiply(*a, *b));
|
|
}
|
|
inline Object operator* (const Object& a, int j)
|
|
{
|
|
return asObject(PyNumber_Multiply(*a, *Int(j)));
|
|
}
|
|
inline Object operator* (const Object& a, double v)
|
|
{
|
|
return asObject(PyNumber_Multiply(*a, *Float(v)));
|
|
}
|
|
inline Object operator* (int j, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Multiply(*Int(j), *b));
|
|
}
|
|
inline Object operator* (double v, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Multiply(*Float(v), *b));
|
|
}
|
|
|
|
inline Object operator/ (const Object& a, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Divide(*a, *b));
|
|
}
|
|
inline Object operator/ (const Object& a, int j)
|
|
{
|
|
return asObject(PyNumber_Divide(*a, *Int(j)));
|
|
}
|
|
inline Object operator/ (const Object& a, double v)
|
|
{
|
|
return asObject(PyNumber_Divide(*a, *Float(v)));
|
|
}
|
|
inline Object operator/ (int j, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Divide(*Int(j), *b));
|
|
}
|
|
inline Object operator/ (double v, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Divide(*Float(v), *b));
|
|
}
|
|
|
|
inline Object operator% (const Object& a, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Remainder(*a, *b));
|
|
}
|
|
inline Object operator% (const Object& a, int j)
|
|
{
|
|
return asObject(PyNumber_Remainder(*a, *Int(j)));
|
|
}
|
|
inline Object operator% (const Object& a, double v)
|
|
{
|
|
return asObject(PyNumber_Remainder(*a, *Float(v)));
|
|
}
|
|
inline Object operator% (int j, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Remainder(*Int(j), *b));
|
|
}
|
|
inline Object operator% (double v, const Object& b)
|
|
{
|
|
return asObject(PyNumber_Remainder(*Float(v), *b));
|
|
}
|
|
|
|
inline Object type(const Exception&) // return the type of the error
|
|
{
|
|
PyObject *ptype, *pvalue, *ptrace;
|
|
PyErr_Fetch(&ptype, &pvalue, &ptrace);
|
|
Object result(ptype);
|
|
PyErr_Restore(ptype, pvalue, ptrace);
|
|
return result;
|
|
}
|
|
|
|
inline Object value(const Exception&) // return the value of the error
|
|
{
|
|
PyObject *ptype, *pvalue, *ptrace;
|
|
PyErr_Fetch(&ptype, &pvalue, &ptrace);
|
|
Object result;
|
|
if(pvalue) result = pvalue;
|
|
PyErr_Restore(ptype, pvalue, ptrace);
|
|
return result;
|
|
}
|
|
|
|
inline Object trace(const Exception&) // return the traceback of the error
|
|
{
|
|
PyObject *ptype, *pvalue, *ptrace;
|
|
PyErr_Fetch(&ptype, &pvalue, &ptrace);
|
|
Object result;
|
|
if(ptrace) result = ptrace;
|
|
PyErr_Restore(ptype, pvalue, ptrace);
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
String seqref<T>::str () const
|
|
{
|
|
return the_item.str();
|
|
}
|
|
|
|
template<typename T>
|
|
String seqref<T>::repr () const
|
|
{
|
|
return the_item.repr();
|
|
}
|
|
|
|
|
|
} // namespace Py
|
|
#endif // __CXX_Objects__h
|