/******************************************** copyright 1999 McMillan Enterprises, Inc. www.mcmillan-inc.com modified for weave by eric jones *********************************************/ #if !defined(SEQUENCE_H_INCLUDED_) #define SEQUENCE_H_INCLUDED_ #include #include #include "object.h" namespace py { //--------------------------------------------------------------------------- // !! This isn't being picked up out of object.h for some reason, so I'll // !! redeclare it. //--------------------------------------------------------------------------- void fail(PyObject*, const char* msg); //--------------------------------------------------------------------------- // base class for list and tuple objects. //--------------------------------------------------------------------------- class sequence : public object { public: //------------------------------------------------------------------------- // constructors //------------------------------------------------------------------------- sequence() : object() {}; sequence(const sequence& other) : object(other) {}; sequence(PyObject* obj) : object(obj) { _violentTypeCheck(); }; //------------------------------------------------------------------------- // destructors //------------------------------------------------------------------------- virtual ~sequence() {} //------------------------------------------------------------------------- // operator= //------------------------------------------------------------------------- virtual sequence& operator=(const sequence& other) { grab_ref(other); return *this; }; /*virtual*/ sequence& operator=(const object& other) { grab_ref(other); _violentTypeCheck(); return *this; }; //------------------------------------------------------------------------- // type checking. //------------------------------------------------------------------------- virtual void _violentTypeCheck() { if (!PySequence_Check(_obj)) { grab_ref(0); fail(PyExc_TypeError, "Not a sequence"); } }; //------------------------------------------------------------------------- // operator+ -- concatenation //------------------------------------------------------------------------- sequence operator+(const sequence& rhs) const { PyObject* rslt = PySequence_Concat(_obj, rhs); if (rslt==0) fail(PyExc_TypeError, "Improper rhs for +"); return lose_ref(rslt); }; //------------------------------------------------------------------------- // count -- count the number of objects in a sequence. //------------------------------------------------------------------------- int count(const object& value) const { int rslt = PySequence_Count(_obj, value); if (rslt == -1) fail(PyExc_RuntimeError, "failure in count"); return rslt; }; int count(int value) const { object val = value; return count(val); }; int count(double value) const { object val = value; return count(val); }; int count(const char* value) const { object val = value; return count(val); }; int count(const std::string& value) const { object val = value.c_str(); return count(val); }; //------------------------------------------------------------------------- // set_item -- virtual so that set_item for tuple and list use // type specific xxx_SetItem function calls. //------------------------------------------------------------------------- virtual void set_item(int ndx, object& val) { int rslt = PySequence_SetItem(_obj, ndx, val); if (rslt==-1) fail(PyExc_IndexError, "Index out of range"); }; //------------------------------------------------------------------------- // operator[] -- non-const version defined in list and tuple sub-types. //------------------------------------------------------------------------- object operator [] (int i) { PyObject* o = PySequence_GetItem(_obj, i); // don't throw error for when [] fails because it might be on left hand // side (a[0] = 1). If the sequence was just created, it will be filled // with NULL values, and setting the values should be ok. However, we // do want to catch index errors that might occur on the right hand side // (obj = a[4] when a has len==3). if (!o) { if (PyErr_ExceptionMatches(PyExc_IndexError)) throw 1; } return lose_ref(o); }; //------------------------------------------------------------------------- // slice -- handles slice operations. // !! NOT TESTED //------------------------------------------------------------------------- sequence slice(int lo, int hi) const { PyObject* o = PySequence_GetSlice(_obj, lo, hi); if (o == 0) fail(PyExc_IndexError, "could not obtain slice"); return lose_ref(o); }; //------------------------------------------------------------------------- // in -- find whether a value is in the given sequence. // overloaded to handle the standard types used in weave. //------------------------------------------------------------------------- bool in(const object& value) const { int rslt = PySequence_In(_obj, value); if (rslt==-1) fail(PyExc_RuntimeError, "problem in in"); return (rslt==1); }; bool in(int value) const { object val = value; return in(val); }; bool in(double value) const { object val = value; return in(val); }; bool in(const std::complex& value) const { object val = value; return in(val); }; bool in(const char* value) const { object val = value; return in(val); }; bool in(const std::string& value) const { object val = value.c_str(); return in(val); }; //------------------------------------------------------------------------- // index -- find whether a value is in the given sequence. // overloaded to handle the standard types used in weave. //------------------------------------------------------------------------- int index(const object& value) const { int rslt = PySequence_Index(_obj, value); if (rslt==-1) fail(PyExc_IndexError, "value not found"); return rslt; }; int index(int value) const { object val = value; return index(val); }; int index(double value) const { object val = value; return index(val); }; int index(const std::complex& value) const { object val = value; return index(val); }; int index(const char* value) const { object val = value; return index(val); }; int index(const std::string& value) const { object val = value; return index(val); }; //------------------------------------------------------------------------- // len, length, size -- find the length of the sequence. // version inherited from py::object ok. //------------------------------------------------------------------------- //------------------------------------------------------------------------- // operator* -- repeat a list multiple times. //------------------------------------------------------------------------- sequence operator * (int count) const { PyObject* rslt = PySequence_Repeat(_obj, count); if (rslt==0) fail(PyExc_RuntimeError, "sequence repeat failed"); return lose_ref(rslt); }; }; //--------------------------------------------------------------------------- // indexed_ref -- return reference obj when operator[] is used as an lvalue. // // list and tuple objects return this for non-const calls to operator[]. // It is similar to object::keyed_ref, except that it stores an integer // index instead of py::object key. //--------------------------------------------------------------------------- class indexed_ref : public object { sequence& _parent; int _ndx; public: indexed_ref(PyObject* obj, sequence& parent, int ndx) : object(obj), _parent(parent), _ndx(ndx) { }; virtual ~indexed_ref() {}; indexed_ref& operator=(const object& other) { grab_ref(other); _parent.set_item(_ndx, *this); return *this; }; indexed_ref& operator=(int other) { object oth = other; return operator=(oth); }; indexed_ref& operator=(double other) { object oth = other; return operator=(oth); }; indexed_ref& operator=(const std::complex& other) { object oth = other; return operator=(oth); }; indexed_ref& operator=(const char* other) { object oth = other; return operator=(oth); }; indexed_ref& operator=(const std::string& other) { object oth = other; return operator=(oth); }; indexed_ref& operator=( const indexed_ref& other ) { object oth = other; return operator=( oth ); } }; } // namespace py #endif // PWOSEQUENCE_H_INCLUDED_