Home | History | Annotate | Download | only in python
      1 /* -----------------------------------------------------------------------------
      2  * pyiterators.swg
      3  *
      4  * Implement a python 'output' iterator for Python 2.2 or higher.
      5  *
      6  * Users can derive form the SwigPyIterator to implement their
      7  * own iterators. As an example (real one since we use it for STL/STD
      8  * containers), the template SwigPyIterator_T does the
      9  * implementation for generic C++ iterators.
     10  * ----------------------------------------------------------------------------- */
     11 
     12 %include <std_common.i>
     13 
     14 %fragment("SwigPyIterator","header",fragment="<stddef.h>") {
     15 namespace swig {
     16   struct stop_iteration {
     17   };
     18 
     19   struct SwigPyIterator {
     20   private:
     21     SwigPtr_PyObject _seq;
     22 
     23   protected:
     24     SwigPyIterator(PyObject *seq) : _seq(seq)
     25     {
     26     }
     27 
     28   public:
     29     virtual ~SwigPyIterator() {}
     30 
     31     // Access iterator method, required by Python
     32     virtual PyObject *value() const = 0;
     33 
     34     // Forward iterator method, required by Python
     35     virtual SwigPyIterator *incr(size_t n = 1) = 0;
     36 
     37     // Backward iterator method, very common in C++, but not required in Python
     38     virtual SwigPyIterator *decr(size_t /*n*/ = 1)
     39     {
     40       throw stop_iteration();
     41     }
     42 
     43     // Random access iterator methods, but not required in Python
     44     virtual ptrdiff_t distance(const SwigPyIterator &/*x*/) const
     45     {
     46       throw std::invalid_argument("operation not supported");
     47     }
     48 
     49     virtual bool equal (const SwigPyIterator &/*x*/) const
     50     {
     51       throw std::invalid_argument("operation not supported");
     52     }
     53 
     54     // C++ common/needed methods
     55     virtual SwigPyIterator *copy() const = 0;
     56 
     57     PyObject *next()
     58     {
     59       SWIG_PYTHON_THREAD_BEGIN_BLOCK; // disable threads
     60       PyObject *obj = value();
     61       incr();
     62       SWIG_PYTHON_THREAD_END_BLOCK; // re-enable threads
     63       return obj;
     64     }
     65 
     66     /* Make an alias for Python 3.x */
     67     PyObject *__next__()
     68     {
     69       return next();
     70     }
     71 
     72     PyObject *previous()
     73     {
     74       SWIG_PYTHON_THREAD_BEGIN_BLOCK; // disable threads
     75       decr();
     76       PyObject *obj = value();
     77       SWIG_PYTHON_THREAD_END_BLOCK; // re-enable threads
     78       return obj;
     79     }
     80 
     81     SwigPyIterator *advance(ptrdiff_t n)
     82     {
     83       return  (n > 0) ?  incr(n) : decr(-n);
     84     }
     85 
     86     bool operator == (const SwigPyIterator& x)  const
     87     {
     88       return equal(x);
     89     }
     90 
     91     bool operator != (const SwigPyIterator& x) const
     92     {
     93       return ! operator==(x);
     94     }
     95 
     96     SwigPyIterator& operator += (ptrdiff_t n)
     97     {
     98       return *advance(n);
     99     }
    100 
    101     SwigPyIterator& operator -= (ptrdiff_t n)
    102     {
    103       return *advance(-n);
    104     }
    105 
    106     SwigPyIterator* operator + (ptrdiff_t n) const
    107     {
    108       return copy()->advance(n);
    109     }
    110 
    111     SwigPyIterator* operator - (ptrdiff_t n) const
    112     {
    113       return copy()->advance(-n);
    114     }
    115 
    116     ptrdiff_t operator - (const SwigPyIterator& x) const
    117     {
    118       return x.distance(*this);
    119     }
    120 
    121     static swig_type_info* descriptor() {
    122       static int init = 0;
    123       static swig_type_info* desc = 0;
    124       if (!init) {
    125 	desc = SWIG_TypeQuery("swig::SwigPyIterator *");
    126 	init = 1;
    127       }
    128       return desc;
    129     }
    130   };
    131 
    132 %#if defined(SWIGPYTHON_BUILTIN)
    133   inline PyObject* make_output_iterator_builtin (PyObject *pyself)
    134   {
    135     Py_INCREF(pyself);
    136     return pyself;
    137   }
    138 %#endif
    139 }
    140 }
    141 
    142 %fragment("SwigPyIterator_T","header",fragment="<stddef.h>",fragment="SwigPyIterator",fragment="StdTraits",fragment="StdIteratorTraits") {
    143 namespace swig {
    144   template<typename OutIterator>
    145   class SwigPyIterator_T :  public SwigPyIterator
    146   {
    147   public:
    148     typedef OutIterator out_iterator;
    149     typedef typename std::iterator_traits<out_iterator>::value_type value_type;
    150     typedef SwigPyIterator_T<out_iterator> self_type;
    151 
    152     SwigPyIterator_T(out_iterator curr, PyObject *seq)
    153       : SwigPyIterator(seq), current(curr)
    154     {
    155     }
    156 
    157     const out_iterator& get_current() const
    158     {
    159       return current;
    160     }
    161 
    162 
    163     bool equal (const SwigPyIterator &iter) const
    164     {
    165       const self_type *iters = dynamic_cast<const self_type *>(&iter);
    166       if (iters) {
    167 	return (current == iters->get_current());
    168       } else {
    169 	throw std::invalid_argument("bad iterator type");
    170       }
    171     }
    172 
    173     ptrdiff_t distance(const SwigPyIterator &iter) const
    174     {
    175       const self_type *iters = dynamic_cast<const self_type *>(&iter);
    176       if (iters) {
    177 	return std::distance(current, iters->get_current());
    178       } else {
    179 	throw std::invalid_argument("bad iterator type");
    180       }
    181     }
    182 
    183   protected:
    184     out_iterator current;
    185   };
    186 
    187   template <class ValueType>
    188   struct from_oper
    189   {
    190     typedef const ValueType& argument_type;
    191     typedef PyObject *result_type;
    192     result_type operator()(argument_type v) const
    193     {
    194       return swig::from(v);
    195     }
    196   };
    197 
    198   template<typename OutIterator,
    199 	   typename ValueType = typename std::iterator_traits<OutIterator>::value_type,
    200 	   typename FromOper = from_oper<ValueType> >
    201   class SwigPyIteratorOpen_T :  public SwigPyIterator_T<OutIterator>
    202   {
    203   public:
    204     FromOper from;
    205     typedef OutIterator out_iterator;
    206     typedef ValueType value_type;
    207     typedef SwigPyIterator_T<out_iterator>  base;
    208     typedef SwigPyIteratorOpen_T<OutIterator, ValueType, FromOper> self_type;
    209 
    210     SwigPyIteratorOpen_T(out_iterator curr, PyObject *seq)
    211       : SwigPyIterator_T<OutIterator>(curr, seq)
    212     {
    213     }
    214 
    215     PyObject *value() const {
    216       return from(static_cast<const value_type&>(*(base::current)));
    217     }
    218 
    219     SwigPyIterator *copy() const
    220     {
    221       return new self_type(*this);
    222     }
    223 
    224     SwigPyIterator *incr(size_t n = 1)
    225     {
    226       while (n--) {
    227 	++base::current;
    228       }
    229       return this;
    230     }
    231 
    232     SwigPyIterator *decr(size_t n = 1)
    233     {
    234       while (n--) {
    235 	--base::current;
    236       }
    237       return this;
    238     }
    239   };
    240 
    241   template<typename OutIterator,
    242 	   typename ValueType = typename std::iterator_traits<OutIterator>::value_type,
    243 	   typename FromOper = from_oper<ValueType> >
    244   class SwigPyIteratorClosed_T :  public SwigPyIterator_T<OutIterator>
    245   {
    246   public:
    247     FromOper from;
    248     typedef OutIterator out_iterator;
    249     typedef ValueType value_type;
    250     typedef SwigPyIterator_T<out_iterator>  base;
    251     typedef SwigPyIteratorClosed_T<OutIterator, ValueType, FromOper> self_type;
    252 
    253     SwigPyIteratorClosed_T(out_iterator curr, out_iterator first, out_iterator last, PyObject *seq)
    254       : SwigPyIterator_T<OutIterator>(curr, seq), begin(first), end(last)
    255     {
    256     }
    257 
    258     PyObject *value() const {
    259       if (base::current == end) {
    260 	throw stop_iteration();
    261       } else {
    262 	return from(static_cast<const value_type&>(*(base::current)));
    263       }
    264     }
    265 
    266     SwigPyIterator *copy() const
    267     {
    268       return new self_type(*this);
    269     }
    270 
    271     SwigPyIterator *incr(size_t n = 1)
    272     {
    273       while (n--) {
    274 	if (base::current == end) {
    275 	  throw stop_iteration();
    276 	} else {
    277 	  ++base::current;
    278 	}
    279       }
    280       return this;
    281     }
    282 
    283     SwigPyIterator *decr(size_t n = 1)
    284     {
    285       while (n--) {
    286 	if (base::current == begin) {
    287 	  throw stop_iteration();
    288 	} else {
    289 	  --base::current;
    290 	}
    291       }
    292       return this;
    293     }
    294 
    295   private:
    296     out_iterator begin;
    297     out_iterator end;
    298   };
    299 
    300   template<typename OutIter>
    301   inline SwigPyIterator*
    302   make_output_iterator(const OutIter& current, const OutIter& begin,const OutIter& end, PyObject *seq = 0)
    303   {
    304     return new SwigPyIteratorClosed_T<OutIter>(current, begin, end, seq);
    305   }
    306 
    307   template<typename OutIter>
    308   inline SwigPyIterator*
    309   make_output_iterator(const OutIter& current, PyObject *seq = 0)
    310   {
    311     return new SwigPyIteratorOpen_T<OutIter>(current, seq);
    312   }
    313 
    314 }
    315 }
    316 
    317 
    318 %fragment("SwigPyIterator");
    319 namespace swig
    320 {
    321   /*
    322     Throw a StopIteration exception
    323   */
    324   %ignore stop_iteration;
    325   struct stop_iteration {};
    326 
    327   %typemap(throws) stop_iteration {
    328     (void)$1;
    329     SWIG_SetErrorObj(PyExc_StopIteration, SWIG_Py_Void());
    330     SWIG_fail;
    331   }
    332 
    333   /*
    334      Mark methods that return new objects
    335   */
    336   %newobject SwigPyIterator::copy;
    337   %newobject SwigPyIterator::operator + (ptrdiff_t n) const;
    338   %newobject SwigPyIterator::operator - (ptrdiff_t n) const;
    339 
    340   %nodirector SwigPyIterator;
    341 
    342 #if defined(SWIGPYTHON_BUILTIN)
    343   %feature("python:tp_iter") SwigPyIterator "&swig::make_output_iterator_builtin";
    344   %feature("python:slot", "tp_iternext", functype="iternextfunc") SwigPyIterator::__next__;
    345 #else
    346   %extend SwigPyIterator {
    347   %pythoncode {def __iter__(self): return self}
    348   }
    349 #endif
    350 
    351   %catches(swig::stop_iteration) SwigPyIterator::value() const;
    352   %catches(swig::stop_iteration) SwigPyIterator::incr(size_t n = 1);
    353   %catches(swig::stop_iteration) SwigPyIterator::decr(size_t n = 1);
    354   %catches(std::invalid_argument) SwigPyIterator::distance(const SwigPyIterator &x) const;
    355   %catches(std::invalid_argument) SwigPyIterator::equal (const SwigPyIterator &x) const;
    356   %catches(swig::stop_iteration) SwigPyIterator::__next__();
    357   %catches(swig::stop_iteration) SwigPyIterator::next();
    358   %catches(swig::stop_iteration) SwigPyIterator::previous();
    359   %catches(swig::stop_iteration) SwigPyIterator::advance(ptrdiff_t n);
    360   %catches(swig::stop_iteration) SwigPyIterator::operator += (ptrdiff_t n);
    361   %catches(swig::stop_iteration) SwigPyIterator::operator -= (ptrdiff_t n);
    362   %catches(swig::stop_iteration) SwigPyIterator::operator + (ptrdiff_t n) const;
    363   %catches(swig::stop_iteration) SwigPyIterator::operator - (ptrdiff_t n) const;
    364 
    365   struct SwigPyIterator
    366   {
    367   protected:
    368     SwigPyIterator(PyObject *seq);
    369 
    370   public:
    371     virtual ~SwigPyIterator();
    372 
    373     // Access iterator method, required by Python
    374     virtual PyObject *value() const = 0;
    375 
    376     // Forward iterator method, required by Python
    377     virtual SwigPyIterator *incr(size_t n = 1) = 0;
    378 
    379     // Backward iterator method, very common in C++, but not required in Python
    380     virtual SwigPyIterator *decr(size_t n = 1);
    381 
    382     // Random access iterator methods, but not required in Python
    383     virtual ptrdiff_t distance(const SwigPyIterator &x) const;
    384 
    385     virtual bool equal (const SwigPyIterator &x) const;
    386 
    387     // C++ common/needed methods
    388     virtual SwigPyIterator *copy() const = 0;
    389 
    390     PyObject *next();
    391     PyObject *__next__();
    392     PyObject *previous();
    393     SwigPyIterator *advance(ptrdiff_t n);
    394 
    395     bool operator == (const SwigPyIterator& x)  const;
    396     bool operator != (const SwigPyIterator& x) const;
    397     SwigPyIterator& operator += (ptrdiff_t n);
    398     SwigPyIterator& operator -= (ptrdiff_t n);
    399     SwigPyIterator* operator + (ptrdiff_t n) const;
    400     SwigPyIterator* operator - (ptrdiff_t n) const;
    401     ptrdiff_t operator - (const SwigPyIterator& x) const;
    402   };
    403 }
    404 
    405