Commit | Line | Data |
---|---|---|
920dae64 AT |
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 | %} |