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