Michele De Stefano's C++ Utilities
sequence_iterator.hpp
Go to the documentation of this file.
1 // sequence_iterator.hpp
2 //
3 // Copyright (c) 2012 - Michele De Stefano (micdestefano@users.sourceforge.net)
4 //
5 // Distributed under the MIT License (See accompanying file LICENSE)
6 
7 #ifndef SEQUENCE_ITERATOR_HPP_INCLUDED
8 #define SEQUENCE_ITERATOR_HPP_INCLUDED
9 
10 #include <Python.h>
11 #include <boost/iterator/iterator_facade.hpp>
12 #include <stdexcept>
14 
15 
35 namespace mds_utils {
36  namespace python {
37 
39 template<class T>
40 class ProxyPySeqElement;
41 
42 template<class T,class Reference = ProxyPySeqElement<T> >
43 class PySequenceIterator;
45 
46 
60 template<class PySeqIt>
62 
63  PySeqIt& seq_it;
64 
65 public:
66 
75  PySeqIt_Access(PySeqIt& it) : seq_it(it) {}
76 
84  PyObject *pPySeq() const { return seq_it.pPySeq; }
85 
93  size_t cur_pos() const { return seq_it.cur_pos; }
94 
102  size_t nel() const { return seq_it.nel; }
103 };
104 
105 
106 
118 template<class T>
120 
122 
123 public:
124 
134  seq_it(*const_cast<PySequenceIterator<T>*>(&it)) {}
135 
137  ProxyPySeqElement& operator =(const T& val);
138 
140  operator T() const;
141 };
142 
143 
144 
145 
164 template<class T,class Reference>
166  public boost::iterator_facade<
167  PySequenceIterator<T>,
168  T,
169  boost::bidirectional_traversal_tag,
170  Reference
171  > {
172 
173 
174  friend class boost::iterator_core_access;
175  friend class PySeqIt_Access< PySequenceIterator<T,Reference> >;
176 
177 
178  PyObject *pPySeq;
179 
180  size_t
181  nel,
182  cur_pos;
183 
184  bool
185  valid_obj;
186 
187  void seq_check(PyObject *o) {
188  if (!PySequence_Check(o)) {
189  throw std::invalid_argument("Input object is not a sequence");
190  }
191  }
192 
193  Reference dereference() const {
194  return Reference(*this);
195  }
196 
197  bool equal(const PySequenceIterator& rhs) const {
198  return cur_pos == rhs.cur_pos;
199  }
200 
201  void increment() { ++cur_pos; }
202 
203  void decrement() { --cur_pos; }
204 
205 public:
206 
215  PySequenceIterator() : pPySeq(NULL),nel(0),cur_pos(0),
216  valid_obj(false) {}
217 
218 
231  PySequenceIterator(PyObject *o,bool end = false) : pPySeq(o),
232  valid_obj(true) {
233 
234  Py_INCREF(pPySeq);
235  seq_check(o);
236  nel = static_cast<size_t>(PySequence_Length(o));
237  cur_pos = (end) ? nel : 0;
238  }
239 
240 
242  PySequenceIterator(const PySequenceIterator& rhs) :
243  pPySeq(rhs.pPySeq),nel(rhs.nel),cur_pos(rhs.cur_pos),
244  valid_obj(rhs.valid_obj) {
245 
246  Py_INCREF(pPySeq);
247  }
248 
249 
252  if (valid_obj) Py_DECREF(pPySeq);
253  }
254 
255 
257  PySequenceIterator& operator =(const PySequenceIterator& rhs) {
258  if (this == &rhs) return *this;
259 
260  if (pPySeq != NULL) Py_DECREF(pPySeq);
261 
262  pPySeq = rhs.pPySeq;
263  Py_INCREF(pPySeq);
264 
265  nel = rhs.nel;
266  cur_pos = rhs.cur_pos;
267  valid_obj = rhs.valid_obj;
268 
269  return *this;
270  }
271 };
272 
274 template<class T>
276  using namespace mds_utils::python;
277 
278  PyObject *v(to_python(val));
279 
280  PySequence_SetItem(seq_it.pPySeq(),seq_it.cur_pos(),v);
281  return *this;
282 }
283 
284 template<class T>
285 inline ProxyPySeqElement<T>::operator T() const {
286  PyObject *py_el(PySequence_GetItem(seq_it.pPySeq(),seq_it.cur_pos()));
287  T retval(get<T>(py_el));
288 
289  Py_DECREF(py_el);
290  return retval;
291 }
292 
293 template<>
294 inline ProxyPySeqElement<PyObject*>::operator PyObject*() const {
295  PyObject *py_el(PySequence_GetItem(seq_it.pPySeq(),seq_it.cur_pos()));
296 
297  return py_el;
298 }
300 
301  } // namespace python
302 } // namespace mds_utils
303 
304 
305 #endif
ProxyPySeqElement(const PySequenceIterator< T > &it)
Constructor.
PyObject * to_python(void)
Converts a value into a Python object.
PyObject * pPySeq() const
Returns the sequence object on which PySequenceIterator is working.
size_t nel() const
Returns the total number of elements of the python sequence.
Main namespace of all Michele De Stefano&#39;s C++ utilities.
Definition: endian.hpp:30
Accessor class for the PySequenceIterator.
PySequenceIterator(PyObject *o, bool end=false)
Constructor that builds the start or the Past-the-end iterator.
PySeqIt_Access(PySeqIt &it)
Constructor.
PySequenceIterator(const PySequenceIterator &rhs)
The copy constructor.
size_t cur_pos() const
Returns the current position of the PySequenceIterator instance.
Utilities for converting data from/to Python.
ProxyPySeqElement & operator=(const T &val)
Assignment.
Namespace of all Michele De Stefano&#39;s C++ Python utilities.
Default Reference type for the PySequenceIterator class.