//----------------------------------*-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

#include "Python.h"
#include "CXX/Version.hxx"
#include "CXX/Config.hxx"
#include "CXX/Exception.hxx"


#include <iostream>
#include STR_STREAM
#include <string>
#include <iterator>
#include <utility>
#include <typeinfo>

#if PY_VERSION_HEX < 0x02050000
typedef int Py_ssize_t;
#    define PY_SSIZE_T_MAX INT_MAX
#    define PY_SSIZE_T_MIN INT_MIN
#endif

namespace Py
	{
	typedef int sequence_index_type;	// type of an index into a sequence

	// Forward declarations
	class Object;
	class Type;
	template<TEMPLATE_TYPENAME T> class SeqBase;
	class String;
	template<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 ) || defined(__GNUG__)
				std::string s("CXX : 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

		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 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();
			}

		// create from bool
		explicit 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());
			}
		// 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 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<long>(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;
			}
		};

	// ===============================================
	// 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<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 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<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::OSTRSTREAM 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 <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator< (const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator> (const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator<=(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator>=(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);

	template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator< (const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator> (const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator<=(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator>=(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_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<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<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::OSTRSTREAM 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 <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME MapBase<T>::iterator& left, const EXPLICIT_TYPENAME MapBase<T>::iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME MapBase<T>::iterator& left, const EXPLICIT_TYPENAME MapBase<T>::iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME MapBase<T>::const_iterator& left, const EXPLICIT_TYPENAME MapBase<T>::const_iterator& right);
	template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME MapBase<T>::const_iterator& left, const EXPLICIT_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
		{
	public:
		// Constructor
		explicit Callable (): Object()  {}
		explicit Callable (PyObject *pyob, bool owned = false): Object (pyob, owned)
			{
			validate();
			}

		Callable (const Object& ob): Object(ob)
			{
			validate();
			}

		// Assignment acquires new ownership of pointer

		Callable& operator= (const Object& rhs)
			{
			return (*this = *rhs);
			}

		Callable& operator= (PyObject* rhsp)
			{
			if(ptr() == rhsp) return *this;
			set (rhsp);
			return *this;
			}

		// Membership
		virtual bool accepts (PyObject *pyob) const
			{
			return pyob && PyCallable_Check (pyob);
			}

		// Call
		Object apply(const Tuple& args) const
			{
			return asObject(PyObject_CallObject(ptr(), args.ptr()));
			}

		// 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(pvalue);
		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 = pvalue;
		PyErr_Restore(ptype, pvalue, ptrace);
		return result;
		}



template<TEMPLATE_TYPENAME T>
String seqref<T>::str () const
			{
			return the_item.str();
			}

template<TEMPLATE_TYPENAME T>
String seqref<T>::repr () const
			{
			return the_item.repr();
			}


	} // namespace Py
#endif	// __CXX_Objects__h


syntax highlighted by Code2HTML, v. 0.9.1