| 1 | // |
| 2 | // Python sequence <-> C++ container wrapper |
| 3 | // |
| 4 | // This wrapper, and its iterator, allows a general use (and reuse) of |
| 5 | // the the mapping between C++ and Python, thanks to the C++ |
| 6 | // templates. |
| 7 | // |
| 8 | // Of course, it needs the C++ compiler to support templates, but |
| 9 | // since we will use this wrapper with the STL containers, that should |
| 10 | // be the case. |
| 11 | // |
| 12 | %{ |
| 13 | #include <iostream> |
| 14 | %} |
| 15 | |
| 16 | /**** The PySequence C++ Wrap ***/ |
| 17 | |
| 18 | %insert(header) %{ |
| 19 | #if PY_VERSION_HEX < 0x02000000 |
| 20 | #define PySequence_Size PySequence_Length |
| 21 | #endif |
| 22 | #include <stdexcept> |
| 23 | %} |
| 24 | |
| 25 | %fragment("PySequence_Base","header") |
| 26 | %{ |
| 27 | namespace swig { |
| 28 | inline size_t |
| 29 | check_index(ptrdiff_t i, size_t size, bool insert = false) { |
| 30 | if ( i < 0 ) { |
| 31 | if ((size_t) (-i) <= size) |
| 32 | return (size_t) (i + size); |
| 33 | } else if ( (size_t) i < size ) { |
| 34 | return (size_t) i; |
| 35 | } else if (insert && ((size_t) i == size)) { |
| 36 | return size; |
| 37 | } |
| 38 | |
| 39 | throw std::out_of_range("index out of range"); |
| 40 | } |
| 41 | |
| 42 | inline size_t |
| 43 | slice_index(ptrdiff_t i, size_t size) { |
| 44 | if ( i < 0 ) { |
| 45 | if ((size_t) (-i) <= size) { |
| 46 | return (size_t) (i + size); |
| 47 | } else { |
| 48 | throw std::out_of_range("index out of range"); |
| 49 | } |
| 50 | } else { |
| 51 | return ( (size_t) i < size ) ? ((size_t) i) : size; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | template <class Sequence, class Difference> |
| 56 | inline typename Sequence::iterator |
| 57 | getpos(Sequence* self, Difference i) { |
| 58 | typename Sequence::iterator pos = self->begin(); |
| 59 | std::advance(pos, check_index(i,self->size())); |
| 60 | return pos; |
| 61 | } |
| 62 | |
| 63 | template <class Sequence, class Difference> |
| 64 | inline typename Sequence::const_iterator |
| 65 | cgetpos(const Sequence* self, Difference i) { |
| 66 | typename Sequence::const_iterator pos = self->begin(); |
| 67 | std::advance(pos, check_index(i,self->size())); |
| 68 | return pos; |
| 69 | } |
| 70 | |
| 71 | template <class Sequence, class Difference> |
| 72 | inline Sequence* |
| 73 | getslice(const Sequence* self, Difference i, Difference j) { |
| 74 | typename Sequence::size_type size = self->size(); |
| 75 | typename Sequence::size_type ii = swig::check_index(i, size); |
| 76 | typename Sequence::size_type jj = swig::slice_index(j, size); |
| 77 | |
| 78 | if (jj > ii) { |
| 79 | typename Sequence::const_iterator vb = self->begin(); |
| 80 | typename Sequence::const_iterator ve = self->begin(); |
| 81 | std::advance(vb,ii); |
| 82 | std::advance(ve,jj); |
| 83 | return new Sequence(vb, ve); |
| 84 | } else { |
| 85 | return new Sequence(); |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | template <class Sequence, class Difference, class InputSeq> |
| 90 | inline void |
| 91 | setslice(Sequence* self, Difference i, Difference j, const InputSeq& v) { |
| 92 | typename Sequence::size_type size = self->size(); |
| 93 | typename Sequence::size_type ii = swig::check_index(i, size, true); |
| 94 | typename Sequence::size_type jj = swig::slice_index(j, size); |
| 95 | if (jj < ii) jj = ii; |
| 96 | typename Sequence::iterator sb = self->begin(); |
| 97 | typename InputSeq::const_iterator vmid = v.begin(); |
| 98 | std::advance(sb,ii); |
| 99 | std::advance(vmid, jj - ii); |
| 100 | self->insert(std::copy(v.begin(), vmid, sb), vmid, v.end()); |
| 101 | } |
| 102 | |
| 103 | template <class Sequence, class Difference> |
| 104 | inline void |
| 105 | delslice(Sequence* self, Difference i, Difference j) { |
| 106 | typename Sequence::size_type size = self->size(); |
| 107 | typename Sequence::size_type ii = swig::check_index(i, size, true); |
| 108 | typename Sequence::size_type jj = swig::slice_index(j, size); |
| 109 | if (jj > ii) { |
| 110 | typename Sequence::iterator sb = self->begin(); |
| 111 | typename Sequence::iterator se = self->begin(); |
| 112 | std::advance(sb,ii); |
| 113 | std::advance(se,jj); |
| 114 | self->erase(sb,se); |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | %} |
| 119 | |
| 120 | %fragment("PySequence_Cont","header", |
| 121 | fragment="StdTraits", |
| 122 | fragment="PySequence_Base", |
| 123 | fragment="PyObject_var") |
| 124 | %{ |
| 125 | #include <iterator> |
| 126 | namespace swig |
| 127 | { |
| 128 | template <class T> |
| 129 | struct PySequence_Ref |
| 130 | { |
| 131 | PySequence_Ref(PyObject* seq, int index) |
| 132 | : _seq(seq), _index(index) |
| 133 | { |
| 134 | } |
| 135 | |
| 136 | operator T () const |
| 137 | { |
| 138 | swig::PyObject_var item = PySequence_GetItem(_seq, _index); |
| 139 | try { |
| 140 | return swig::as<T>(item, true); |
| 141 | } catch (std::exception& e) { |
| 142 | char msg[1024]; |
| 143 | PyOS_snprintf(msg, sizeof(msg), "in sequence element %d ", _index); |
| 144 | if (!PyErr_Occurred()) { |
| 145 | SWIG_type_error(swig::type_name<T>(), item); |
| 146 | } |
| 147 | SWIG_append_errmsg(msg); |
| 148 | SWIG_append_errmsg(e.what()); |
| 149 | throw; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | PySequence_Ref& operator=(const T& v) |
| 154 | { |
| 155 | PySequence_SetItem(_seq, _index, swig::from<T>(v)); |
| 156 | return *this; |
| 157 | } |
| 158 | |
| 159 | private: |
| 160 | PyObject* _seq; |
| 161 | int _index; |
| 162 | }; |
| 163 | |
| 164 | template <class T> |
| 165 | struct PySequence_ArrowProxy |
| 166 | { |
| 167 | PySequence_ArrowProxy(const T& x): m_value(x) {} |
| 168 | const T* operator->() const { return &m_value; } |
| 169 | operator const T*() const { return &m_value; } |
| 170 | T m_value; |
| 171 | }; |
| 172 | |
| 173 | template <class T, class Reference > |
| 174 | struct PySequence_Iter |
| 175 | { |
| 176 | typedef PySequence_Iter<T, Reference > self; |
| 177 | |
| 178 | typedef std::random_access_iterator_tag iterator_category; |
| 179 | typedef Reference reference; |
| 180 | typedef T value_type; |
| 181 | typedef T* pointer; |
| 182 | typedef int difference_type; |
| 183 | |
| 184 | PySequence_Iter() |
| 185 | { |
| 186 | } |
| 187 | |
| 188 | PySequence_Iter(PyObject* seq, int index) |
| 189 | : _seq(seq), _index(index) |
| 190 | { |
| 191 | } |
| 192 | |
| 193 | reference operator*() const |
| 194 | { |
| 195 | return reference(_seq, _index); |
| 196 | } |
| 197 | |
| 198 | PySequence_ArrowProxy<T> |
| 199 | operator->() const { |
| 200 | return PySequence_ArrowProxy<T>(operator*()); |
| 201 | } |
| 202 | |
| 203 | bool operator==(const self& ri) const |
| 204 | { |
| 205 | return (_index == ri._index) && (_seq == ri._seq); |
| 206 | } |
| 207 | |
| 208 | bool operator!=(const self& ri) const |
| 209 | { |
| 210 | return !(operator==(ri)); |
| 211 | } |
| 212 | |
| 213 | self& operator ++ () |
| 214 | { |
| 215 | ++_index; |
| 216 | return *this; |
| 217 | } |
| 218 | |
| 219 | self& operator -- () |
| 220 | { |
| 221 | --_index; |
| 222 | return *this; |
| 223 | } |
| 224 | |
| 225 | self& operator += (difference_type n) |
| 226 | { |
| 227 | _index += n; |
| 228 | return *this; |
| 229 | } |
| 230 | |
| 231 | self operator +(difference_type n) const |
| 232 | { |
| 233 | return self(_seq, _index + n); |
| 234 | } |
| 235 | |
| 236 | self& operator -= (difference_type n) |
| 237 | { |
| 238 | _index -= n; |
| 239 | return *this; |
| 240 | } |
| 241 | |
| 242 | self operator -(difference_type n) const |
| 243 | { |
| 244 | return self(_seq, _index - n); |
| 245 | } |
| 246 | |
| 247 | difference_type operator - (const self& ri) const |
| 248 | { |
| 249 | return _index - ri._index; |
| 250 | } |
| 251 | |
| 252 | reference |
| 253 | operator[](difference_type n) const |
| 254 | { |
| 255 | return reference(_seq, _index + n); |
| 256 | } |
| 257 | |
| 258 | private: |
| 259 | PyObject* _seq; |
| 260 | int _index; |
| 261 | }; |
| 262 | |
| 263 | template <class T> |
| 264 | struct PySequence_Cont |
| 265 | { |
| 266 | typedef PySequence_Ref<T> reference; |
| 267 | typedef const PySequence_Ref<T> const_reference; |
| 268 | typedef T value_type; |
| 269 | typedef T* pointer; |
| 270 | typedef int difference_type; |
| 271 | typedef int size_type; |
| 272 | typedef const pointer const_pointer; |
| 273 | typedef PySequence_Iter<T, reference> iterator; |
| 274 | typedef PySequence_Iter<T, const_reference> const_iterator; |
| 275 | |
| 276 | PySequence_Cont(PyObject* seq) : _seq(0) |
| 277 | { |
| 278 | if (!PySequence_Check(seq)) { |
| 279 | throw std::invalid_argument("a sequence is expected"); |
| 280 | } |
| 281 | _seq = seq; |
| 282 | Py_INCREF(_seq); |
| 283 | } |
| 284 | |
| 285 | ~PySequence_Cont() |
| 286 | { |
| 287 | if (_seq) Py_DECREF(_seq); |
| 288 | } |
| 289 | |
| 290 | size_type size() const |
| 291 | { |
| 292 | return PySequence_Size(_seq); |
| 293 | } |
| 294 | |
| 295 | bool empty() const |
| 296 | { |
| 297 | return size() == 0; |
| 298 | } |
| 299 | |
| 300 | iterator begin() |
| 301 | { |
| 302 | return iterator(_seq, 0); |
| 303 | } |
| 304 | |
| 305 | const_iterator begin() const |
| 306 | { |
| 307 | return const_iterator(_seq, 0); |
| 308 | } |
| 309 | |
| 310 | iterator end() |
| 311 | { |
| 312 | return iterator(_seq, size()); |
| 313 | } |
| 314 | |
| 315 | const_iterator end() const |
| 316 | { |
| 317 | return const_iterator(_seq, size()); |
| 318 | } |
| 319 | |
| 320 | reference operator[](difference_type n) |
| 321 | { |
| 322 | return reference(_seq, n); |
| 323 | } |
| 324 | |
| 325 | const_reference operator[](difference_type n) const |
| 326 | { |
| 327 | return const_reference(_seq, n); |
| 328 | } |
| 329 | |
| 330 | bool check(bool set_err = true) const |
| 331 | { |
| 332 | int s = size(); |
| 333 | for (int i = 0; i < s; ++i) { |
| 334 | swig::PyObject_var item = PySequence_GetItem(_seq, i); |
| 335 | if (!swig::check<value_type>(item)) { |
| 336 | if (set_err) { |
| 337 | char msg[1024]; |
| 338 | PyOS_snprintf(msg, sizeof(msg), "in sequence element %d", i); |
| 339 | SWIG_type_error(swig::type_name<value_type>(), item); |
| 340 | SWIG_append_errmsg(msg); |
| 341 | } |
| 342 | return 0; |
| 343 | } |
| 344 | } |
| 345 | return 1; |
| 346 | } |
| 347 | |
| 348 | private: |
| 349 | PyObject* _seq; |
| 350 | }; |
| 351 | |
| 352 | } |
| 353 | %} |
| 354 | |
| 355 | |
| 356 | /**** The python container methods ****/ |
| 357 | |
| 358 | |
| 359 | %define %swig_container_methods(Container...) |
| 360 | |
| 361 | %newobject __getslice__; |
| 362 | |
| 363 | %extend { |
| 364 | bool __nonzero__() const { |
| 365 | return !(self->empty()); |
| 366 | } |
| 367 | |
| 368 | size_type __len__() const { |
| 369 | return self->size(); |
| 370 | } |
| 371 | } |
| 372 | %enddef |
| 373 | |
| 374 | %define %swig_sequence_methods_common(Sequence...) |
| 375 | %swig_container_methods(SWIG_arg(Sequence)) |
| 376 | %fragment("PySequence_Base"); |
| 377 | |
| 378 | %extend { |
| 379 | value_type pop() throw (std::out_of_range) { |
| 380 | if (self->size() == 0) |
| 381 | throw std::out_of_range("pop from empty container"); |
| 382 | Sequence::value_type x = self->back(); |
| 383 | self->pop_back(); |
| 384 | return x; |
| 385 | } |
| 386 | |
| 387 | Sequence* __getslice__(difference_type i, difference_type j) throw (std::out_of_range) { |
| 388 | return swig::getslice(self, i, j); |
| 389 | } |
| 390 | |
| 391 | void __setslice__(difference_type i, difference_type j, const Sequence& v) throw (std::out_of_range, std::invalid_argument) { |
| 392 | swig::setslice(self, i, j, v); |
| 393 | } |
| 394 | |
| 395 | void __delslice__(difference_type i, difference_type j) throw (std::out_of_range) { |
| 396 | swig::delslice(self, i, j); |
| 397 | } |
| 398 | |
| 399 | void __delitem__(difference_type i) throw (std::out_of_range) { |
| 400 | self->erase(swig::getpos(self,i)); |
| 401 | } |
| 402 | } |
| 403 | %enddef |
| 404 | |
| 405 | %define %swig_sequence_methods(Sequence...) |
| 406 | %swig_sequence_methods_common(SWIG_arg(Sequence)) |
| 407 | %extend { |
| 408 | const value_type& __getitem__(difference_type i) const throw (std::out_of_range) { |
| 409 | return *(swig::cgetpos(self, i)); |
| 410 | } |
| 411 | |
| 412 | void __setitem__(difference_type i, const value_type& x) throw (std::out_of_range) { |
| 413 | *(swig::getpos(self,i)) = x; |
| 414 | } |
| 415 | |
| 416 | void append(const value_type& x) { |
| 417 | self->push_back(x); |
| 418 | } |
| 419 | } |
| 420 | %enddef |
| 421 | |
| 422 | %define %swig_sequence_methods_val(Sequence...) |
| 423 | %swig_sequence_methods_common(SWIG_arg(Sequence)) |
| 424 | %extend { |
| 425 | value_type __getitem__(difference_type i) throw (std::out_of_range) { |
| 426 | return *(swig::cgetpos(self, i)); |
| 427 | } |
| 428 | |
| 429 | void __setitem__(difference_type i, value_type x) throw (std::out_of_range) { |
| 430 | *(swig::getpos(self,i)) = x; |
| 431 | } |
| 432 | |
| 433 | void append(value_type x) { |
| 434 | self->push_back(x); |
| 435 | } |
| 436 | } |
| 437 | %enddef |
| 438 | |
| 439 | |
| 440 | // |
| 441 | // Common fragments |
| 442 | // |
| 443 | |
| 444 | %fragment("StdSequenceTraits","header", |
| 445 | fragment="StdTraits",fragment="PyObject_var", |
| 446 | fragment="PySequence_Cont") |
| 447 | %{ |
| 448 | namespace swig { |
| 449 | template <class PySeq, class Seq> |
| 450 | inline void |
| 451 | assign(const PySeq& pyseq, Seq* seq) { |
| 452 | #ifdef SWIG_STD_NOASSIGN_STL |
| 453 | typedef typename PySeq::value_type value_type; |
| 454 | typename PySeq::const_iterator it = pyseq.begin(); |
| 455 | for (;it != pyseq.end(); ++it) { |
| 456 | seq->insert(seq->end(),(value_type)(*it)); |
| 457 | } |
| 458 | #else |
| 459 | seq->assign(pyseq.begin(), pyseq.end()); |
| 460 | #endif |
| 461 | } |
| 462 | |
| 463 | template <class Seq, class T = typename Seq::value_type > |
| 464 | struct traits_asptr_stdseq { |
| 465 | typedef Seq sequence; |
| 466 | typedef T value_type; |
| 467 | |
| 468 | static int asptr(PyObject *obj, sequence **seq) { |
| 469 | if (PySequence_Check(obj)) { |
| 470 | try { |
| 471 | PySequence_Cont<value_type> pyseq(obj); |
| 472 | if (seq) { |
| 473 | sequence *pseq = new sequence(); |
| 474 | assign(pyseq, pseq); |
| 475 | *seq = pseq; |
| 476 | return SWIG_NEWOBJ; |
| 477 | } else { |
| 478 | return pyseq.check(); |
| 479 | } |
| 480 | } catch (std::exception& e) { |
| 481 | if (seq) { |
| 482 | if (!PyErr_Occurred()) |
| 483 | PyErr_SetString(PyExc_TypeError, e.what()); |
| 484 | } |
| 485 | return 0; |
| 486 | } |
| 487 | } else { |
| 488 | sequence *p; |
| 489 | if (SWIG_ConvertPtr(obj,(void**)&p, |
| 490 | swig::type_info<sequence>(),0) != -1) { |
| 491 | if (seq) *seq = p; |
| 492 | return 1; |
| 493 | } |
| 494 | } |
| 495 | if (seq) { |
| 496 | PyErr_Format(PyExc_TypeError, "a %s is expected", |
| 497 | swig::type_name<sequence>()); |
| 498 | } |
| 499 | return 0; |
| 500 | } |
| 501 | }; |
| 502 | |
| 503 | template <class Seq, class T = typename Seq::value_type > |
| 504 | struct traits_from_stdseq { |
| 505 | typedef Seq sequence; |
| 506 | typedef T value_type; |
| 507 | typedef typename Seq::size_type size_type; |
| 508 | typedef typename sequence::const_iterator const_iterator; |
| 509 | |
| 510 | static PyObject *from(const sequence& seq) { |
| 511 | size_type size = seq.size(); |
| 512 | if (size <= (size_type)INT_MAX) { |
| 513 | PyObject *obj = PyTuple_New((int)size); |
| 514 | int i = 0; |
| 515 | for (const_iterator it = seq.begin(); |
| 516 | it != seq.end(); ++it, ++i) { |
| 517 | PyTuple_SetItem(obj,i,swig::from<value_type>(*it)); |
| 518 | } |
| 519 | return obj; |
| 520 | } else { |
| 521 | PyErr_SetString(PyExc_OverflowError, |
| 522 | "sequence size not valid in python"); |
| 523 | return NULL; |
| 524 | } |
| 525 | } |
| 526 | }; |
| 527 | } |
| 528 | %} |