7 #ifndef MDS_UTILS_PYTHON_SEQUENCE_HPP_INCLUDED 8 #define MDS_UTILS_PYTHON_SEQUENCE_HPP_INCLUDED 11 #include <boost/fusion/include/for_each.hpp> 12 #include <boost/fusion/include/size.hpp> 13 #include <boost/lexical_cast.hpp> 54 inline size_t len(PyObject *o) {
55 Py_ssize_t retval(PySequence_Length(o));
58 throw std::runtime_error(
"Cannot retrieve the length");
61 return static_cast<size_t>(retval);
93 template<
class Derived>
96 class from_fusion_seq {
104 from_fusion_seq(Derived& seq) :
self(seq),pos(0) {}
106 template <
typename T>
108 from_fusion_seq* pself(const_cast<from_fusion_seq*>(
this));
109 if (!
self.set_item(pself->pos++,x)) {
110 throw std::runtime_error(
"Failed to insert element n. " +
111 boost::lexical_cast<std::string>(pos-1) +
112 " into Python sequence");
117 friend class from_fusion_seq;
126 PyObject* get_item()
const {
127 PyObject* po = PySequence_GetItem(m_seq,m_i);
128 if (po == NULL)
throw std::runtime_error(
129 "Cannot access element " +
130 boost::lexical_cast<std::string>(m_i));
139 operator PyObject* () {
154 int success(PySequence_SetItem(m_seq,m_i,v));
159 throw std::runtime_error(
"Cannot assign to element " +
160 boost::lexical_cast<std::string>(m_i));
180 size_t idx(
long i)
const {
181 long Nel(static_cast<long>(m_len));
182 if (i < -Nel || i >= Nel)
throw std::invalid_argument(
183 "Cannot access element " +
184 boost::lexical_cast<std::string>(i));
185 if (i >= 0)
return static_cast<size_t>(i);
186 return static_cast<size_t>(i+Nel);
231 assert(Derived::self_type_check(*
this));
232 m_len = PySequence_Size(po);
238 assert(Derived::self_type_check(*
this));
239 m_len = PySequence_Size(
m_po);
245 assert(Derived::self_type_check(*
this));
246 m_len = PySequence_Size(
m_po);
259 assert(Derived::self_type_check(*
this));
260 m_len = PySequence_Size(
m_po);
295 template<
class seq_T>
296 void set(
const seq_T& seq) {
299 m_len = boost::fusion::size(seq);
300 m_po = Derived::new_seq(m_len);
302 throw std::runtime_error(
"Could not instantiate a new sequence");
305 Derived&
self(*
static_cast<Derived*
>(
this));
307 boost::fusion::for_each(seq,from_fusion_seq(
self));
330 void set(FwIt b,FwIt e) {
334 Derived&
self(*
static_cast<Derived*
>(
this));
336 size_t m_len(std::distance(b,e));
338 m_po = Derived::new_seq(m_len);
341 throw std::runtime_error(
"Could not instantiate a new sequence");
348 for (k = 0;k <
m_len;++k,++b) {
350 throw std::runtime_error(
"Failed to insert " 352 boost::lexical_cast<std::string>(k) +
353 " into Python sequence");
376 if (!PySequence_Check(o)) {
377 throw std::invalid_argument(
"Cannot construct a sequence from " 378 "a non-sequence object.");
383 m_len = PySequence_Size(o);
385 if (Derived::self_type_check(o)) {
392 if ((
m_po = Derived::new_seq(m_len)) == NULL) {
393 throw std::runtime_error(
"Could not instantiate a new sequence");
402 Derived&
self(*
static_cast<Derived*
>(
this));
404 for (k = 0;k <
m_len;++k,po = NULL) {
406 po = PySequence_GetItem(o,k);
409 throw std::runtime_error(
410 "Failed extracting sequence element n. " +
411 boost::lexical_cast<std::string>(k) +
412 " from the input sequence");
415 if (!
self.set_item(k,po)) {
416 throw std::runtime_error(
"Failed to insert " 418 boost::lexical_cast<std::string>(k) +
419 " into Python sequence");
427 if (PySequence_DelItem(*
this,
idx(i)) == -1) {
428 throw std::runtime_error(
"Cannot delete item.");
447 return ProxyElem(*
this,
idx(i));
471 static PyObject* new_seq(
size_t len) {
472 return PyList_New(len);
475 static bool self_type_check(
const Obj& o) {
476 return PySequence_Check(o);
480 bool set_item(
size_t pos,T
const& x) {
482 bool retval(PySequence_SetItem(
m_po,pos,po) == 0);
Proxy class for managing attribute access.
Wraps a generic Python sequence.
void reset()
Resets the object to the state given by the default constructor.
Sequence(ProxyAttr &&rhs)
The move constructor from ProxyAttr objects.
Sequence_Base(const Sequence_Base &rhs)
The copy-constructor.
virtual void incref()
Increments the reference count using Py_XINCREF.
PyObject * to_python(void)
Converts a value into a Python object.
Sequence(Sequence &&rhs)
The move constructor.
Sequence_Base(size_t len)
Creates a sequence of the desired length.
Main namespace of all Michele De Stefano's C++ utilities.
Obj()
Default constructor.
Sequence(PyObject *po)
Constructs a new Sequence from a Python sequence.
Sequence_Base(ProxyAttr &&rhs)
Move constructor from ProxyAttr object.
Sequence()
The default constructor.
PyObject * m_po
Underlying pointer to the wrapped Python object.
size_t len() const
Returns the length of the sequence.
Contains a wrapper class for the PyObject* datatype.
Sequence_Base()
Default constructor.
Sequence(const Sequence &rhs)
The copy constructor.
void get_ownership()
Used in place of incref, when the wrapped PyObject* was increfed already.
void del(long i)
Deletes the item in position i.
ProxyElem operator[](long i)
Element access.
size_t len(PyObject *o)
Retrieves the length of a sequence object.
Obj operator()()
Calling operator.
Obj & operator=(const Obj &rhs)
Standard assignment.
Sequence_Base< Derived > & operator=(Sequence_Base< Derived > &&rhs)
Move assignment.
size_t m_len
The length of the sequence.
Sequence_Base(Sequence_Base &&rhs)
Move constructor.
Sequence_Base(PyObject *po)
Constructs a new Sequence_Base from a Python sequence.
size_t idx(long i) const
Converts a Python index (that can also be negative) into a C index.
Base class for all generic sequence types.
This is a simple wrapper around the PyObject* datatype.