Synopsis - Cross-Reference

File: /src/Synopsis/Python/Object.hh
  1//
  2// Copyright (C) 2004 Stefan Seefeld
  3// All rights reserved.
  4// Licensed to the public under the terms of the GNU LGPL (>= 2),
  5// see the file COPYING for details.
  6//
  7
  8#ifndef _Synopsis_Python_Object_hh
  9#define _Synopsis_Python_Object_hh
 10
 11#include <Python.h>
 12#include <string>
 13#include <stdexcept>
 14#include <iostream>
 15
 16#if PY_VERSION_HEX >= 0x02030000
 17# define PYTHON_HAS_BOOL 1
 18#else
 19# define PYTHON_HAS_BOOL 0
 20#endif
 21
 22#if PY_VERSION_HEX < 0x02050000
 23typedef int Py_ssize_t;
 24#endif
 25
 26namespace Synopsis
 27{
 28namespace Python
 29{
 30
 31class List;
 32class Tuple;
 33class Dict;
 34class Module;
 35class Interpreter;
 36
 37//. Object provides basic
 38//. functionality to access the underlaying
 39//. python object, to be used in subclasses and
 40//. generic accessors such as (python) lists and tuples
 41class Object
 42{
 43  friend class List;
 44  friend class Tuple;
 45  friend class Dict;
 46  friend class Module;
 47  friend class Interpreter;
 48public:
 49  struct TypeError : std::invalid_argument
 50  {
 51    TypeError(const std::string &msg = "") : std::invalid_argument(msg) {}
 52  };
 53
 54  struct AttributeError : std::invalid_argument
 55  {
 56    AttributeError(const std::string &msg = "") : std::invalid_argument(msg) {}
 57  };
 58
 59  struct KeyError : std::invalid_argument
 60  {
 61    KeyError(const std::string &msg = "") : std::invalid_argument(msg) {}
 62  };
 63
 64  struct ImportError : std::invalid_argument
 65  {
 66    ImportError(const std::string &msg = "") : std::invalid_argument(msg) {}
 67  };
 68
 69  Object() : my_impl(Py_None) { Py_INCREF(Py_None);}
 70  Object(PyObject *);
 71  Object(const Object &o) : my_impl(o.my_impl) { Py_INCREF(my_impl);}
 72  Object(const std::string &value) : my_impl(PyString_FromString(value.c_str())) {}
 73  Object(const char *value) : my_impl(PyString_FromString(value)) {}
 74  Object(char value) : my_impl(PyString_FromStringAndSize(&value, 1)) {}
 75  Object(double value) : my_impl(PyFloat_FromDouble(value)) {}
 76  Object(int value) : my_impl(PyInt_FromLong(value)) {}
 77  Object(unsigned int value) : my_impl(PyInt_FromLong(value)) {}
 78  Object(long value) : my_impl(PyInt_FromLong(value)) {}
 79  Object(bool value) : my_impl(PyInt_FromLong(value)) {}
 80  virtual ~Object() { Py_DECREF(my_impl);}
 81  Object &operator = (const Object &o);
 82   
 83  int hash() const { return PyObject_Hash(my_impl);}
 84  operator bool () const 
 85  {
 86    int retn = PyObject_IsTrue(my_impl);
 87    if (retn == -1) check_exception();
 88    return retn == 1;
 89  }
 90  Object type() const { return PyObject_Type(my_impl);}
 91  Object repr() const { return PyObject_Repr(my_impl);}
 92  Object str() const { return PyObject_Str(my_impl);}
 93  int cmp(Object o) const;
 94  Object boolean() const { return PyObject_IsTrue(my_impl);}
 95  bool is_instance(Object) const;
 96  void assert_type(const char *module,
 97		   const char *type) const
 98    throw(TypeError);
 99
100  //. callable interface
101  Object operator () ();
102  Object operator () (Tuple);
103  Object operator () (Tuple, Dict);
104
105  Object get(Object) const;
106
107  //. try to downcast to T, throw on failure
108  template <typename T>
109  static T narrow(Object) throw(TypeError);
110  //. more relaxed form of downcast, return None on failure
111  template <typename T>
112  static T try_narrow(Object);
113  static Object import(const std::string &name);
114
115  Object attr(const std::string &) const;
116  bool set_attr(const std::string &, Object);
117  PyObject *ref() { Py_INCREF(my_impl); return my_impl;}
118  int ref_count() const { return my_impl->ob_refcnt;}
119private:
120  //. check for an exception and if set translate into
121  //. a C++ exception that is thrown
122  void check_exception() const;
123  
124  PyObject *my_impl;
125};
126
127inline bool operator == (Object o1, Object o2) { return !o1.cmp(o2);}
128inline bool operator < (Object o1, Object o2) { return o1.cmp(o2) < 0;}
129inline bool operator > (Object o1, Object o2) { return o1.cmp(o2)> 0;}
130
131class Tuple : public Object
132{
133public:
134  Tuple() : Object(PyTuple_New(0)) {}
135  explicit Tuple(PyObject *);
136  size_t size() const { return PyTuple_GET_SIZE(my_impl);}
137  bool empty() const { return !size();}
138  Tuple(Object);
139  Tuple(Object, Object);
140  Tuple(Object, Object, Object);
141  Tuple(Object, Object, Object, Object);
142  Tuple(Object, Object, Object, Object, Object);
143  Tuple(Object, Object, Object, Object, Object, Object);
144  Tuple(Object, Object, Object, Object, Object, Object, Object);
145  Tuple(Object, Object, Object, Object, Object, Object, Object, Object);
146  Tuple(Object, Object, Object, Object, Object, Object, Object, Object, Object);
147  Object get(size_t i) const;
148};
149
150class List : public Object
151{
152public:
153  class iterator;
154  class reverse_iterator;
155
156  List(size_t i = 0) : Object(PyList_New(i)) {}
157  List(Object) throw(TypeError);
158  template <typename I>
159  List(I begin, I end);
160  Tuple tuple() const { return Tuple(PyList_AsTuple(my_impl));}
161  size_t size() const { return PyList_GET_SIZE(my_impl);}
162  bool empty() const { return !size();}
163  void set(int i, Object o);
164  Object get(int i) const;
165  void append(Object o) { PyList_Append(my_impl, o.my_impl);}
166  void insert(int i, Object o) { PyList_Insert(my_impl, i, o.my_impl);}
167  void extend(List l);
168  void del(int i) { PySequence_DelItem(my_impl, i);}
169
170  iterator begin() const;
171  iterator end() const;
172  iterator erase(iterator);
173
174  reverse_iterator rbegin() const;
175  reverse_iterator rend() const;
176
177  List get_slice(int low, int high) const;
178  List copy() const { return get_slice(0, -1);}
179  bool sort() { return PyList_Sort(my_impl) == 0;}
180  bool reverse() { return PyList_Reverse(my_impl) == 0;}
181private:
182  PyObject *impl() { return my_impl;} // extend friendship
183};
184
185class List::iterator
186{
187  friend class List;
188public:
189  iterator(const iterator &i)
190    : my_list(i.my_list), my_pos(i.my_pos), my_current(i.my_current) {}
191  iterator &operator = (const iterator &);
192
193  bool operator == (iterator i);
194  bool operator != (iterator i) { return !operator==(i);}
195
196  const Object &operator *() { return my_current;}
197  const Object *operator ->() { return &(operator *());}
198  iterator operator ++(int) { incr(); return *this;}
199  iterator operator ++() { iterator tmp = *this; incr(); return tmp;}
200  iterator operator +(int i);
201  iterator operator --(int) { decr(); return *this;}
202  iterator operator --() { iterator tmp = *this; decr(); return tmp;}
203  iterator operator -(int i);
204
205private:
206  iterator(List l, int i) : my_list(l), my_pos(i) 
207  { if (my_pos >= 0) my_current = my_list.get(my_pos);}
208  void incr();
209  void decr();
210
211  List my_list;
212  Py_ssize_t my_pos;
213
214  Object my_current;
215};
216
217class List::reverse_iterator
218{
219  friend class List;
220public:
221  reverse_iterator(const reverse_iterator &i)
222    : my_list(i.my_list), my_pos(i.my_pos), my_current(i.my_current) {}
223  reverse_iterator &operator = (const reverse_iterator &);
224
225  bool operator == (reverse_iterator i);
226  bool operator != (reverse_iterator i) { return !operator==(i);}
227
228  const Object &operator *() { return my_current;}
229  const Object *operator ->() { return &(operator *());}
230  reverse_iterator operator ++(int) { incr(); return *this;}
231  reverse_iterator operator ++() { reverse_iterator tmp = *this; incr(); return tmp;}
232  reverse_iterator operator +(int i);
233  reverse_iterator operator --(int) { decr(); return *this;}
234  reverse_iterator operator --() { reverse_iterator tmp = *this; decr(); return tmp;}
235  reverse_iterator operator -(int i);
236
237private:
238  reverse_iterator(List l, int i) : my_list(l), my_pos(i) 
239  { if (my_pos >= 0) my_current = my_list.get(my_pos);}
240  void incr();
241  void decr();
242
243  List my_list;
244  Py_ssize_t my_pos;
245
246  Object my_current;
247};
248
249class Dict : public Object
250{
251public:
252  class iterator;
253  friend class iterator;
254   
255  Dict() : Object(PyDict_New()) {}
256  Dict(Object o) throw(TypeError) : Object(o) 
257  { if (!PyDict_Check(o.my_impl)) throw TypeError("object not a dict");}
258  void set(Object k, Object v);
259  Object get(Object k, Object d = Object()) const;
260  bool has_key(Object k) const;
261  bool del(Object k);
262
263  iterator begin() const;
264  iterator end() const;
265   
266  void clear() { PyDict_Clear(my_impl);}
267  Dict copy() const { return Object(PyDict_Copy(my_impl));}
268  bool update(Dict d) { return PyDict_Update(my_impl, d.my_impl) == 0;}
269   
270  List keys() const { return List(Object(PyDict_Keys(my_impl)));}
271  List values() const { return List(Object(PyDict_Values(my_impl)));}
272  List items() const { return List(Object(PyDict_Items(my_impl)));}
273
274private:
275  PyObject *impl() { return my_impl;} // extend friendship
276};
277
278class Dict::iterator
279{
280  friend class Dict;
281public:
282  iterator(const iterator &i) : my_dict(i.my_dict), my_pos(i.my_pos) {}
283  iterator &operator = (const iterator &);
284
285  bool operator == (iterator i);
286  bool operator != (iterator i) { return !operator==(i);}
287
288  const Tuple &operator *() { return my_current;}
289  const Tuple *operator ->() { return &(operator *());}
290  iterator operator ++(int) { incr(); return *this;}
291  iterator operator ++() { iterator tmp = *this; incr(); return tmp;}
292
293private:
294  iterator(Dict, int);
295  void incr();
296
297  Dict my_dict;
298  Py_ssize_t my_pos;
299
300  Tuple my_current;
301};
302
303inline Object::Object(PyObject *o)
304  : my_impl(o)
305{
306  if (!my_impl)
307  {
308    check_exception();
309    my_impl = Py_None;
310    Py_INCREF(Py_None);
311  }
312}
313
314inline Object &Object::operator = (const Object &o)
315{
316  if (my_impl != o.my_impl)
317  {
318    Py_DECREF(my_impl);
319    my_impl = o.my_impl;
320    Py_INCREF(my_impl);
321  }
322  return *this;
323}
324
325inline int Object::cmp(Object o) const 
326{
327  int result = PyObject_Compare(my_impl, o.my_impl);
328  check_exception();
329  return result;
330}
331
332inline bool Object::is_instance(Object o) const
333{
334  return PyObject_IsInstance(my_impl, o.my_impl) == 1;
335}
336
337inline void Object::assert_type(const char *module_name,
338				const char *type_name) const
339  throw(TypeError)
340{
341  Object module = Object::import(module_name);
342  if (!is_instance(module.attr(type_name)))
343  {
344    std::string msg = "object not a ";
345    msg += module_name;
346    msg += ".";
347    msg += type_name;
348    msg += " (was ";
349    Object type = attr("__class__").repr();
350    msg += PyString_AS_STRING(type.my_impl);
351    msg += ")";
352    throw TypeError(msg);
353  }
354}
355
356inline Object Object::import(const std::string &name)
357{
358  PyObject *retn = PyImport_ImportModule(const_cast<char *>(name.c_str()));
359  if (!retn) throw ImportError(name);
360  else return Object(retn);
361}
362
363inline Object Object::attr(const std::string &name) const
364{
365  PyObject *retn = PyObject_GetAttrString(my_impl, const_cast<char *>(name.c_str()));
366  if (!retn) throw AttributeError(name.c_str());
367  else return Object(retn);
368}
369
370inline bool Object::set_attr(const std::string &name, Object value)
371{
372  int retn = PyObject_SetAttrString(my_impl,
373				    const_cast<char *>(name.c_str()),
374				    value.ref());
375  return retn != -1;
376}
377
378inline Object Object::get(Object k) const 
379{
380  PyObject *retn = PyObject_GetItem(my_impl, k.my_impl);
381  if (!retn) check_exception();
382  Py_INCREF(retn);
383  return Object(retn);
384}
385
386
387template <typename T>
388inline T Object::narrow(Object o) throw(Object::TypeError)
389{
390  T retn(o.my_impl);
391  Py_INCREF(o.my_impl);
392  return retn;
393}
394
395template <typename T>
396inline T Object::try_narrow(Object o)
397{
398  try 
399  {
400    T retn(o.my_impl);
401    Py_INCREF(o.my_impl);
402    return retn;
403  }
404  catch (const TypeError &) { return T();}
405}
406
407template <>
408inline char Object::narrow(Object o) throw(Object::TypeError)
409{
410  if (!PyString_Check(o.my_impl) || PyString_GET_SIZE(o.my_impl) != 1)
411    throw TypeError("object not a character");
412  char *value;
413  Py_ssize_t length;
414  PyString_AsStringAndSize(o.my_impl, &value, &length);
415  return value[0];
416}
417
418template <>
419inline const char *Object::narrow(Object o) throw(Object::TypeError)
420{
421  if (!PyString_Check(o.my_impl)) throw TypeError("object not a string");
422  return PyString_AS_STRING(o.my_impl);
423}
424
425template <>
426inline std::string Object::narrow(Object o) throw(Object::TypeError)
427{
428  if (!PyString_Check(o.my_impl)) throw TypeError("object not a string");
429  return PyString_AS_STRING(o.my_impl);
430}
431
432template <>
433inline double Object::narrow(Object o) throw(Object::TypeError)
434{
435  if (!PyFloat_Check(o.my_impl)) throw TypeError("object not a float");
436  return PyFloat_AsDouble(o.my_impl);
437}
438
439template <>
440inline long Object::narrow(Object o) throw(Object::TypeError)
441{
442  if (!PyInt_Check(o.my_impl)) throw TypeError("object not an integer");
443  return PyInt_AsLong(o.my_impl);
444}
445
446template <>
447inline bool Object::narrow(Object o) throw(Object::TypeError)
448{
449#if 0 //PYTHON_HAS_BOOL
450  if (!PyBool_Check(o.my_impl)) throw TypeError("object not a boolean");
451#else
452  if (!PyInt_Check(o.my_impl)) throw TypeError("object not an integer");
453#endif
454  return PyInt_AsLong(o.my_impl);
455}
456
457inline void Object::check_exception() const
458{
459  PyObject *exc = PyErr_Occurred();
460  if (!exc) return;
461  PyObject *type, *value, *trace;
462  //  PyErr_Print();
463  PyErr_Fetch(&type, &value, &trace);
464  Object t(type), v(value), tr(trace); // to release the reference at end of scope
465  std::cerr << trace << ' ' << Object::narrow<std::string>(tr.str()) << std::endl;
466  if (exc == PyExc_KeyError)
467    throw KeyError(Object::narrow<std::string>(v.str()));
468  else if (exc == PyExc_TypeError)
469    throw TypeError(Object::narrow<std::string>(v.str()));
470  else if (exc == PyExc_AttributeError)
471    throw AttributeError();
472  throw std::runtime_error(PyString_AsString(value));
473}
474
475inline std::ostream &operator << (std::ostream &os, const Object &o)
476{
477  return os << Object::narrow<std::string>(o.str());
478}
479
480inline Object Object::operator () ()
481{
482  return PyObject_CallObject(my_impl, 0);
483}
484
485inline Object Object::operator () (Tuple args)
486{
487  return PyObject_Call(my_impl, args.my_impl, 0);
488}
489
490inline Object Object::operator () (Tuple args, Dict kwds)
491{
492  return PyObject_Call(my_impl, args.my_impl, kwds.my_impl);
493}
494
495inline Tuple::Tuple(PyObject *o)
496  : Object(o)
497{
498  if (!PyTuple_Check(o)) throw TypeError("object not a tuple");
499}
500
501inline Tuple::Tuple(Object o)
502  : Object(PyTuple_New(1))
503{
504   PyTuple_SET_ITEM(my_impl, 0, o.my_impl);
505   Py_INCREF(o.my_impl);
506}
507
508inline Tuple::Tuple(Object o1, Object o2)
509  : Object(PyTuple_New(2))
510{
511   PyTuple_SET_ITEM(my_impl, 0, o1.my_impl);
512   Py_INCREF(o1.my_impl);
513   PyTuple_SET_ITEM(my_impl, 1, o2.my_impl);
514   Py_INCREF(o2.my_impl);
515}
516
517inline Tuple::Tuple(Object o1, Object o2, Object o3)
518  : Object(PyTuple_New(3))
519{
520   PyTuple_SET_ITEM(my_impl, 0, o1.my_impl);
521   Py_INCREF(o1.my_impl);
522   PyTuple_SET_ITEM(my_impl, 1, o2.my_impl);
523   Py_INCREF(o2.my_impl);
524   PyTuple_SET_ITEM(my_impl, 2, o3.my_impl);
525   Py_INCREF(o3.my_impl);
526}
527
528inline Tuple::Tuple(Object o1, Object o2, Object o3,
529		    Object o4)
530  : Object(PyTuple_New(4))
531{
532   PyTuple_SET_ITEM(my_impl, 0, o1.my_impl);
533   Py_INCREF(o1.my_impl);
534   PyTuple_SET_ITEM(my_impl, 1, o2.my_impl);
535   Py_INCREF(o2.my_impl);
536   PyTuple_SET_ITEM(my_impl, 2, o3.my_impl);
537   Py_INCREF(o3.my_impl);
538   PyTuple_SET_ITEM(my_impl, 3, o4.my_impl);
539   Py_INCREF(o4.my_impl);
540}
541
542inline Tuple::Tuple(Object o1, Object o2, Object o3,
543		    Object o4, Object o5)
544  : Object(PyTuple_New(5))
545{
546   PyTuple_SET_ITEM(my_impl, 0, o1.my_impl);
547   Py_INCREF(o1.my_impl);
548   PyTuple_SET_ITEM(my_impl, 1, o2.my_impl);
549   Py_INCREF(o2.my_impl);
550   PyTuple_SET_ITEM(my_impl, 2, o3.my_impl);
551   Py_INCREF(o3.my_impl);
552   PyTuple_SET_ITEM(my_impl, 3, o4.my_impl);
553   Py_INCREF(o4.my_impl);
554   PyTuple_SET_ITEM(my_impl, 4, o5.my_impl);
555   Py_INCREF(o5.my_impl);
556}
557
558inline Tuple::Tuple(Object o1, Object o2, Object o3,
559		    Object o4, Object o5, Object o6)
560  : Object(PyTuple_New(6))
561{
562   PyTuple_SET_ITEM(my_impl, 0, o1.my_impl);
563   Py_INCREF(o1.my_impl);
564   PyTuple_SET_ITEM(my_impl, 1, o2.my_impl);
565   Py_INCREF(o2.my_impl);
566   PyTuple_SET_ITEM(my_impl, 2, o3.my_impl);
567   Py_INCREF(o3.my_impl);
568   PyTuple_SET_ITEM(my_impl, 3, o4.my_impl);
569   Py_INCREF(o4.my_impl);
570   PyTuple_SET_ITEM(my_impl, 4, o5.my_impl);
571   Py_INCREF(o5.my_impl);
572   PyTuple_SET_ITEM(my_impl, 5, o6.my_impl);
573   Py_INCREF(o6.my_impl);
574}
575
576inline Tuple::Tuple(Object o1, Object o2, Object o3,
577		    Object o4, Object o5, Object o6,
578		    Object o7)
579  : Object(PyTuple_New(7))
580{
581   PyTuple_SET_ITEM(my_impl, 0, o1.my_impl);
582   Py_INCREF(o1.my_impl);
583   PyTuple_SET_ITEM(my_impl, 1, o2.my_impl);
584   Py_INCREF(o2.my_impl);
585   PyTuple_SET_ITEM(my_impl, 2, o3.my_impl);
586   Py_INCREF(o3.my_impl);
587   PyTuple_SET_ITEM(my_impl, 3, o4.my_impl);
588   Py_INCREF(o4.my_impl);
589   PyTuple_SET_ITEM(my_impl, 4, o5.my_impl);
590   Py_INCREF(o5.my_impl);
591   PyTuple_SET_ITEM(my_impl, 5, o6.my_impl);
592   Py_INCREF(o6.my_impl);
593   PyTuple_SET_ITEM(my_impl, 6, o7.my_impl);
594   Py_INCREF(o7.my_impl);
595}
596
597inline Tuple::Tuple(Object o1, Object o2, Object o3,
598		    Object o4, Object o5, Object o6,
599		    Object o7, Object o8)
600  : Object(PyTuple_New(8))
601{
602   PyTuple_SET_ITEM(my_impl, 0, o1.my_impl);
603   Py_INCREF(o1.my_impl);
604   PyTuple_SET_ITEM(my_impl, 1, o2.my_impl);
605   Py_INCREF(o2.my_impl);
606   PyTuple_SET_ITEM(my_impl, 2, o3.my_impl);
607   Py_INCREF(o3.my_impl);
608   PyTuple_SET_ITEM(my_impl, 3, o4.my_impl);
609   Py_INCREF(o4.my_impl);
610   PyTuple_SET_ITEM(my_impl, 4, o5.my_impl);
611   Py_INCREF(o5.my_impl);
612   PyTuple_SET_ITEM(my_impl, 5, o6.my_impl);
613   Py_INCREF(o6.my_impl);
614   PyTuple_SET_ITEM(my_impl, 6, o7.my_impl);
615   Py_INCREF(o7.my_impl);
616   PyTuple_SET_ITEM(my_impl, 7, o8.my_impl);
617   Py_INCREF(o8.my_impl);
618}
619
620inline Tuple::Tuple(Object o1, Object o2, Object o3,
621		    Object o4, Object o5, Object o6,
622		    Object o7, Object o8, Object o9)
623  : Object(PyTuple_New(9))
624{
625   PyTuple_SET_ITEM(my_impl, 0, o1.my_impl);
626   Py_INCREF(o1.my_impl);
627   PyTuple_SET_ITEM(my_impl, 1, o2.my_impl);
628   Py_INCREF(o2.my_impl);
629   PyTuple_SET_ITEM(my_impl, 2, o3.my_impl);
630   Py_INCREF(o3.my_impl);
631   PyTuple_SET_ITEM(my_impl, 3, o4.my_impl);
632   Py_INCREF(o4.my_impl);
633   PyTuple_SET_ITEM(my_impl, 4, o5.my_impl);
634   Py_INCREF(o5.my_impl);
635   PyTuple_SET_ITEM(my_impl, 5, o6.my_impl);
636   Py_INCREF(o6.my_impl);
637   PyTuple_SET_ITEM(my_impl, 6, o7.my_impl);
638   Py_INCREF(o7.my_impl);
639   PyTuple_SET_ITEM(my_impl, 7, o8.my_impl);
640   Py_INCREF(o8.my_impl);
641   PyTuple_SET_ITEM(my_impl, 8, o9.my_impl);
642   Py_INCREF(o9.my_impl);
643}
644
645inline Object Tuple::get(size_t i) const 
646{
647  PyObject *retn = PyTuple_GetItem(my_impl, i);
648  if (!retn) check_exception();
649  Py_INCREF(retn);
650  return Object(retn);
651}
652
653
654inline List::List(Object o) throw(TypeError)
655  : Object(o)
656{
657  if (PyTuple_Check(o.my_impl)) // copy elements into new list
658  {
659    Py_DECREF(my_impl);
660    my_impl = PyList_New(PyTuple_Size(o.my_impl));
661    for (int i = 0; i != PyList_Size(my_impl); ++i)
662    {
663      PyObject *item = PyTuple_GetItem(o.my_impl, i);
664      Py_INCREF(item);
665      PyList_SetItem(my_impl, i, item);
666    }
667  }
668  else if (!PyList_Check(o.my_impl)) throw TypeError("object not a list");
669}
670
671template <typename I>
672List::List(I begin, I end)
673  : Object(PyList_New(0))
674{
675  for (I i = begin; i != end; ++i) append(*i);
676}
677
678inline void List::set(int i, Object o)
679{
680  Py_INCREF(o.my_impl);
681  PyList_SetItem(my_impl, i, o.my_impl);
682}
683
684inline Object List::get(int i) const
685{
686  PyObject *retn = PyList_GetItem(my_impl, i);
687  if (!retn) check_exception();
688  Py_INCREF(retn);
689  return Object(retn);
690}
691
692inline void List::extend(List l) 
693{
694  for (List::iterator i = l.begin(); i != l.end(); ++i)
695    append(*i);
696}
697
698inline List::iterator List::begin() const
699{
700  return iterator(*this, size() ? 0 : -1);
701}
702
703inline List::iterator List::end() const
704{
705  return iterator(*this, -1);
706}
707
708inline List::iterator List::erase(List::iterator i)
709{
710  if (i.my_pos >= 0) del(i.my_pos);
711  if (i.my_pos >= size()) // if the erased element was the last...
712    --i.my_pos;           // ... decrement the iterator by one
713  return i;
714}
715
716inline List::reverse_iterator List::rbegin() const
717{
718  return reverse_iterator(*this, size() - 1);
719}
720
721inline List::reverse_iterator List::rend() const
722{
723  return reverse_iterator(*this, -1);
724}
725
726inline List List::get_slice(int low, int high) const 
727{
728  return List(PyList_GetSlice(my_impl, low, high));
729}
730
731inline List::iterator &List::iterator::operator = (const List::iterator &i)
732{
733  my_list = i.my_list;
734  my_pos = i.my_pos;
735  my_current = i.my_current;
736  return *this;
737}
738
739inline bool List::iterator::operator == (List::iterator i)
740{
741  return i.my_list.impl() == my_list.impl() && i.my_pos == my_pos;
742}
743
744inline List::iterator List::iterator::operator + (int i)
745{
746  if (my_pos != -1) my_pos += i;
747
748  if (my_pos < my_list.size())
749    my_current = my_list.get(my_pos);
750  else
751    my_pos = -1;
752  return *this;
753}
754
755inline List::iterator List::iterator::operator - (int i)
756{
757  my_pos = my_pos == -1 ? my_list.size() - i : my_pos - i;
758
759  if (my_pos > -1)
760    my_current = my_list.get(my_pos);
761  else
762    my_pos = -1;
763  return *this;
764}
765
766inline void List::iterator::incr() 
767{
768  operator + (1);
769}
770
771inline void List::iterator::decr() 
772{
773  operator - (1);
774}
775
776inline bool List::reverse_iterator::operator == (List::reverse_iterator i)
777{
778  return i.my_list.impl() == my_list.impl() && i.my_pos == my_pos;
779}
780
781inline List::reverse_iterator List::reverse_iterator::operator + (int i)
782{
783  my_pos = my_pos == -1 ? my_list.size() - i : my_pos - i;
784
785  if (my_pos > -1)
786    my_current = my_list.get(my_pos);
787  else
788    my_pos = -1;
789  return *this;
790}
791
792inline List::reverse_iterator List::reverse_iterator::operator - (int i)
793{
794  my_pos += i;
795
796  if (my_pos < my_list.size())
797    my_current = my_list.get(my_pos);
798  else
799    my_pos = -1;
800  return *this;
801}
802
803inline void List::reverse_iterator::incr() 
804{
805  operator + (1);
806}
807
808inline void List::reverse_iterator::decr() 
809{
810  operator - (1);
811}
812
813inline void Dict::set(Object k, Object v)
814{
815  PyObject_SetItem(my_impl, k.my_impl, v.my_impl);
816}
817
818inline Object Dict::get(Object k, Object d) const
819{
820  PyObject *retn = PyDict_GetItem(my_impl, k.my_impl);
821  if (retn) Py_INCREF(retn);
822  return retn ? Object(retn) : d;
823}
824
825inline bool Dict::has_key(Object k) const 
826{
827  return PyObject_GetItem(my_impl, k.my_impl) != 0;
828}
829
830inline bool Dict::del(Object k)
831{
832  return PyObject_DelItem(my_impl, k.my_impl) == 0;
833}
834
835inline Dict::iterator Dict::begin() const
836{
837  return iterator(*this, 0);
838}
839
840inline Dict::iterator Dict::end() const
841{
842  return iterator(*this, -1);
843}
844
845inline Dict::iterator::iterator(Dict dict, int pos)
846  : my_dict(dict), my_pos(pos)
847{
848  if (pos != -1) incr();
849}
850
851inline Dict::iterator &Dict::iterator::operator = (const Dict::iterator &i)
852{
853  my_dict = i.my_dict;
854  my_pos = i.my_pos;
855  my_current = i.my_current;
856  return *this;
857}
858
859inline void Dict::iterator::incr()
860{
861  PyObject *key = 0, *value = 0;
862  bool valid = PyDict_Next(my_dict.impl(), &my_pos, &key, &value);
863  if (!valid) my_pos = -1;
864  else
865  {
866     Py_INCREF(key);
867     Py_INCREF(value);   
868     my_current = Tuple(key, value);
869  }
870}
871
872inline bool Dict::iterator::operator == (Dict::iterator i)
873{
874  return i.my_dict.impl() == my_dict.impl() && i.my_pos == my_pos;
875}
876
877}
878}
879
880#endif