PageRenderTime 23ms CodeModel.GetById 14ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/Lib/python/pyiterators.swg

#
Unknown | 404 lines | 338 code | 66 blank | 0 comment | 0 complexity | c297c6c14928286c229f0d2362cf4806 MD5 | raw file
  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>") {
 15namespace 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") {
143namespace 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");
319namespace 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