Add std::array container wrappers for Python
These work much like any of the other STL containers except Python slicing is somewhat limited because the array is a fixed size. Only slices of the full size are supported.
This commit is contained in:
parent
4e8ea4e853
commit
55bbf68512
8 changed files with 500 additions and 57 deletions
|
|
@ -252,6 +252,12 @@ namespace swig {
|
|||
return pos;
|
||||
}
|
||||
|
||||
template <class Sequence>
|
||||
inline void
|
||||
erase(Sequence* seq, const typename Sequence::iterator& position) {
|
||||
seq->erase(position);
|
||||
}
|
||||
|
||||
template <class Sequence, class Difference>
|
||||
inline Sequence*
|
||||
getslice(const Sequence* self, Difference i, Difference j, Py_ssize_t step) {
|
||||
|
|
@ -552,6 +558,7 @@ namespace swig
|
|||
difference_type _index;
|
||||
};
|
||||
|
||||
// STL container wrapper around a Python sequence
|
||||
template <class T>
|
||||
struct SwigPySequence_Cont
|
||||
{
|
||||
|
|
@ -748,7 +755,6 @@ namespace swig
|
|||
return self->size();
|
||||
}
|
||||
}
|
||||
|
||||
%enddef
|
||||
|
||||
|
||||
|
|
@ -756,7 +762,7 @@ namespace swig
|
|||
%define %swig_sequence_methods_common(Sequence...)
|
||||
%swig_sequence_iterator(%arg(Sequence))
|
||||
%swig_container_methods(%arg(Sequence))
|
||||
|
||||
|
||||
%fragment("SwigPySequence_Base");
|
||||
|
||||
#if defined(SWIGPYTHON_BUILTIN)
|
||||
|
|
@ -769,14 +775,6 @@ namespace swig
|
|||
#endif // SWIGPYTHON_BUILTIN
|
||||
|
||||
%extend {
|
||||
value_type pop() throw (std::out_of_range) {
|
||||
if (self->size() == 0)
|
||||
throw std::out_of_range("pop from empty container");
|
||||
Sequence::value_type x = self->back();
|
||||
self->pop_back();
|
||||
return x;
|
||||
}
|
||||
|
||||
/* typemap for slice object support */
|
||||
%typemap(in) PySliceObject* {
|
||||
if (!PySlice_Check($input)) {
|
||||
|
|
@ -794,7 +792,11 @@ namespace swig
|
|||
return swig::getslice(self, i, j, 1);
|
||||
}
|
||||
|
||||
void __setslice__(difference_type i, difference_type j, const Sequence& v = Sequence()) throw (std::out_of_range, std::invalid_argument) {
|
||||
void __setslice__(difference_type i, difference_type j) throw (std::out_of_range, std::invalid_argument) {
|
||||
swig::setslice(self, i, j, 1, Sequence());
|
||||
}
|
||||
|
||||
void __setslice__(difference_type i, difference_type j, const Sequence& v) throw (std::out_of_range, std::invalid_argument) {
|
||||
swig::setslice(self, i, j, 1, v);
|
||||
}
|
||||
|
||||
|
|
@ -803,11 +805,10 @@ namespace swig
|
|||
}
|
||||
#endif
|
||||
|
||||
void __delitem__(difference_type i) throw (std::out_of_range) {
|
||||
self->erase(swig::getpos(self,i));
|
||||
void __delitem__(difference_type i) throw (std::out_of_range, std::invalid_argument) {
|
||||
swig::erase(self, swig::getpos(self, i));
|
||||
}
|
||||
|
||||
|
||||
/* Overloaded methods for Python 3 compatibility
|
||||
* (Also useful in Python 2.x)
|
||||
*/
|
||||
|
|
@ -858,12 +859,11 @@ namespace swig
|
|||
Sequence::difference_type jd = j;
|
||||
swig::delslice(self, id, jd, step);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
%enddef
|
||||
|
||||
%define %swig_sequence_methods(Sequence...)
|
||||
%define %swig_sequence_methods_non_resizable(Sequence...)
|
||||
%swig_sequence_methods_common(%arg(Sequence))
|
||||
%extend {
|
||||
const value_type& __getitem__(difference_type i) const throw (std::out_of_range) {
|
||||
|
|
@ -876,19 +876,32 @@ namespace swig
|
|||
|
||||
#if defined(SWIGPYTHON_BUILTIN)
|
||||
// This will be called through the mp_ass_subscript slot to delete an entry.
|
||||
void __setitem__(difference_type i) throw (std::out_of_range) {
|
||||
self->erase(swig::getpos(self,i));
|
||||
void __setitem__(difference_type i) throw (std::out_of_range, std::invalid_argument) {
|
||||
swig::erase(self, swig::getpos(self, i));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
%enddef
|
||||
|
||||
%define %swig_sequence_methods(Sequence...)
|
||||
%swig_sequence_methods_non_resizable(%arg(Sequence))
|
||||
%extend {
|
||||
value_type pop() throw (std::out_of_range) {
|
||||
if (self->size() == 0)
|
||||
throw std::out_of_range("pop from empty container");
|
||||
Sequence::value_type x = self->back();
|
||||
self->pop_back();
|
||||
return x;
|
||||
}
|
||||
|
||||
void append(const value_type& x) {
|
||||
self->push_back(x);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
%enddef
|
||||
|
||||
%define %swig_sequence_methods_val(Sequence...)
|
||||
%define %swig_sequence_methods_non_resizable_val(Sequence...)
|
||||
%swig_sequence_methods_common(%arg(Sequence))
|
||||
%extend {
|
||||
value_type __getitem__(difference_type i) throw (std::out_of_range) {
|
||||
|
|
@ -901,16 +914,28 @@ namespace swig
|
|||
|
||||
#if defined(SWIGPYTHON_BUILTIN)
|
||||
// This will be called through the mp_ass_subscript slot to delete an entry.
|
||||
void __setitem__(difference_type i) throw (std::out_of_range) {
|
||||
self->erase(swig::getpos(self,i));
|
||||
void __setitem__(difference_type i) throw (std::out_of_range, std::invalid_argument) {
|
||||
swig::erase(self, swig::getpos(self, i));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
%enddef
|
||||
|
||||
%define %swig_sequence_methods_val(Sequence...)
|
||||
%swig_sequence_methods_non_resizable_val(%arg(Sequence))
|
||||
%extend {
|
||||
value_type pop() throw (std::out_of_range) {
|
||||
if (self->size() == 0)
|
||||
throw std::out_of_range("pop from empty container");
|
||||
Sequence::value_type x = self->back();
|
||||
self->pop_back();
|
||||
return x;
|
||||
}
|
||||
|
||||
void append(value_type x) {
|
||||
self->push_back(x);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
%enddef
|
||||
|
||||
|
||||
|
|
|
|||
91
Lib/python/std_array.i
Normal file
91
Lib/python/std_array.i
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
std::array
|
||||
*/
|
||||
|
||||
%fragment("StdArrayTraits","header",fragment="StdSequenceTraits")
|
||||
%{
|
||||
namespace swig {
|
||||
template <class T, size_t N>
|
||||
struct traits_asptr<std::array<T, N> > {
|
||||
static int asptr(PyObject *obj, std::array<T, N> **vec) {
|
||||
return traits_asptr_stdseq<std::array<T, N> >::asptr(obj, vec);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, size_t N>
|
||||
struct traits_from<std::array<T, N> > {
|
||||
static PyObject *from(const std::array<T, N>& vec) {
|
||||
return traits_from_stdseq<std::array<T, N> >::from(vec);
|
||||
}
|
||||
};
|
||||
|
||||
template <class SwigPySeq, class T, size_t N>
|
||||
inline void
|
||||
assign(const SwigPySeq& swigpyseq, std::array<T, N>* seq) {
|
||||
if (swigpyseq.size() < seq->size())
|
||||
throw std::invalid_argument("std::array cannot be expanded in size");
|
||||
else if (swigpyseq.size() > seq->size())
|
||||
throw std::invalid_argument("std::array cannot be reduced in size");
|
||||
std::copy(swigpyseq.begin(), swigpyseq.end(), seq->begin());
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
inline void
|
||||
erase(std::array<T, N>* seq, const typename std::array<T, N>::iterator& position) {
|
||||
throw std::invalid_argument("std::array object does not support item deletion");
|
||||
}
|
||||
|
||||
// Only limited slicing is supported as std::array is fixed in size
|
||||
template <class T, size_t N, class Difference>
|
||||
inline std::array<T, N>*
|
||||
getslice(const std::array<T, N>* self, Difference i, Difference j, Py_ssize_t step) {
|
||||
using Sequence = std::array<T, N>;
|
||||
typename Sequence::size_type size = self->size();
|
||||
Difference ii = 0;
|
||||
Difference jj = 0;
|
||||
swig::slice_adjust(i, j, step, size, ii, jj);
|
||||
|
||||
if (step == 1 && ii == 0 && jj == size) {
|
||||
Sequence *sequence = new Sequence();
|
||||
std::copy(self->begin(), self->end(), sequence->begin());
|
||||
return sequence;
|
||||
} else if (step == -1 && ii == (size - 1) && jj == -1) {
|
||||
Sequence *sequence = new Sequence();
|
||||
std::copy(self->rbegin(), self->rend(), sequence->begin());
|
||||
return sequence;
|
||||
} else {
|
||||
throw std::invalid_argument("std::array object only supports getting a slice that is the size of the array");
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, size_t N, class Difference, class InputSeq>
|
||||
inline void
|
||||
setslice(std::array<T, N>* self, Difference i, Difference j, Py_ssize_t step, const InputSeq& is = InputSeq()) {
|
||||
using Sequence = std::array<T, N>;
|
||||
typename Sequence::size_type size = self->size();
|
||||
Difference ii = 0;
|
||||
Difference jj = 0;
|
||||
swig::slice_adjust(i, j, step, size, ii, jj, true);
|
||||
|
||||
if (step == 1 && ii == 0 && jj == size) {
|
||||
std::copy(is.begin(), is.end(), self->begin());
|
||||
} else if (step == -1 && ii == (size - 1) && jj == -1) {
|
||||
std::copy(is.rbegin(), is.rend(), self->begin());
|
||||
} else {
|
||||
throw std::invalid_argument("std::array object only supports setting a slice that is the size of the array");
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, size_t N, class Difference>
|
||||
inline void
|
||||
delslice(std::array<T, N>* self, Difference i, Difference j, Py_ssize_t step) {
|
||||
throw std::invalid_argument("std::array object does not support item deletion");
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
#define %swig_array_methods(Type...) %swig_sequence_methods_non_resizable(Type)
|
||||
#define %swig_array_methods_val(Type...) %swig_sequence_methods_non_resizable_val(Type);
|
||||
|
||||
%include <std/std_array.i>
|
||||
|
||||
88
Lib/std/std_array.i
Normal file
88
Lib/std/std_array.i
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// std::array
|
||||
//
|
||||
|
||||
%include <std_container.i>
|
||||
|
||||
%define %std_array_methods(array...)
|
||||
%std_sequence_methods_non_resizable(array)
|
||||
void fill(const value_type& u);
|
||||
%enddef
|
||||
|
||||
|
||||
%define %std_array_methods_val(array...)
|
||||
%std_sequence_methods_non_resizable_val(array)
|
||||
void fill(const value_type& u);
|
||||
%enddef
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// std::array
|
||||
//
|
||||
// The aim of all that follows would be to integrate std::array with
|
||||
// as much as possible, namely, to allow the user to pass and
|
||||
// be returned tuples or lists.
|
||||
// const declarations are used to guess the intent of the function being
|
||||
// exported; therefore, the following rationale is applied:
|
||||
//
|
||||
// -- f(std::array<T, N>), f(const std::array<T, N>&):
|
||||
// the parameter being read-only, either a sequence or a
|
||||
// previously wrapped std::array<T, N> can be passed.
|
||||
// -- f(std::array<T, N>&), f(std::array<T, N>*):
|
||||
// the parameter may be modified; therefore, only a wrapped std::array
|
||||
// can be passed.
|
||||
// -- std::array<T, N> f(), const std::array<T, N>& f():
|
||||
// the array is returned by copy; therefore, a sequence of T:s
|
||||
// is returned which is most easily used in other functions
|
||||
// -- std::array<T, N>& f(), std::array<T, N>* f():
|
||||
// the array is returned by reference; therefore, a wrapped std::array
|
||||
// is returned
|
||||
// -- const std::array<T, N>* f(), f(const std::array<T, N>*):
|
||||
// for consistency, they expect and return a plain array pointer.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
%{
|
||||
#include <array>
|
||||
%}
|
||||
|
||||
// exported classes
|
||||
|
||||
namespace std {
|
||||
|
||||
template<class _Tp, size_t _Nm >
|
||||
class array {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef _Tp value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef const value_type* const_pointer;
|
||||
typedef _Tp& reference;
|
||||
typedef const _Tp& const_reference;
|
||||
|
||||
%traits_swigtype(_Tp);
|
||||
%traits_enum(_Tp);
|
||||
|
||||
%fragment(SWIG_Traits_frag(std::array<_Tp, _Nm >), "header",
|
||||
fragment=SWIG_Traits_frag(_Tp),
|
||||
fragment="StdArrayTraits") {
|
||||
namespace swig {
|
||||
template <> struct traits<std::array<_Tp, _Nm > > {
|
||||
typedef pointer_category category;
|
||||
static const char* type_name() {
|
||||
return "std::array<" #_Tp "," #_Nm " >";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
%typemap_traits_ptr(SWIG_TYPECHECK_STDARRAY, std::array<_Tp, _Nm >);
|
||||
|
||||
#ifdef %swig_array_methods
|
||||
// Add swig/language extra methods
|
||||
%swig_array_methods(std::array<_Tp, _Nm >);
|
||||
#endif
|
||||
|
||||
%std_array_methods(array);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -6,20 +6,17 @@
|
|||
#include <algorithm>
|
||||
%}
|
||||
|
||||
// Common container methods
|
||||
// Common non-resizable container methods
|
||||
|
||||
%define %std_container_methods_non_resizable(container...)
|
||||
|
||||
%define %std_container_methods(container...)
|
||||
container();
|
||||
container(const container&);
|
||||
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
void clear();
|
||||
|
||||
void swap(container& v);
|
||||
|
||||
allocator_type get_allocator() const;
|
||||
|
||||
#ifdef SWIG_EXPORT_ITERATOR_METHODS
|
||||
class iterator;
|
||||
class reverse_iterator;
|
||||
|
|
@ -34,17 +31,27 @@
|
|||
|
||||
%enddef
|
||||
|
||||
// Common container methods
|
||||
|
||||
%define %std_container_methods(container...)
|
||||
%std_container_methods_non_resizable(%arg(container))
|
||||
|
||||
void clear();
|
||||
allocator_type get_allocator() const;
|
||||
|
||||
%enddef
|
||||
|
||||
// Common sequence
|
||||
|
||||
%define %std_sequence_methods_common(sequence)
|
||||
|
||||
|
||||
%std_container_methods(%arg(sequence));
|
||||
|
||||
|
||||
sequence(size_type size);
|
||||
void pop_back();
|
||||
|
||||
|
||||
void resize(size_type new_size);
|
||||
|
||||
|
||||
#ifdef SWIG_EXPORT_ITERATOR_METHODS
|
||||
%extend {
|
||||
// %extend wrapper used for differing definitions of these methods introduced in C++11
|
||||
|
|
@ -52,24 +59,31 @@
|
|||
iterator erase(iterator first, iterator last) { return $self->erase(first, last); }
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
%enddef
|
||||
|
||||
%define %std_sequence_methods_non_resizable(sequence)
|
||||
|
||||
%define %std_sequence_methods(sequence)
|
||||
|
||||
%std_sequence_methods_common(%arg(sequence));
|
||||
|
||||
sequence(size_type size, const value_type& value);
|
||||
void push_back(const value_type& x);
|
||||
%std_container_methods_non_resizable(%arg(sequence))
|
||||
|
||||
const value_type& front() const;
|
||||
const value_type& back() const;
|
||||
|
||||
void assign(size_type n, const value_type& x);
|
||||
|
||||
%enddef
|
||||
|
||||
%define %std_sequence_methods(sequence)
|
||||
|
||||
%std_sequence_methods_common(%arg(sequence));
|
||||
|
||||
sequence(size_type size, const value_type& value);
|
||||
void push_back(const value_type& x);
|
||||
|
||||
const value_type& front() const;
|
||||
const value_type& back() const;
|
||||
|
||||
void assign(size_type n, const value_type& x);
|
||||
void resize(size_type new_size, const value_type& x);
|
||||
|
||||
|
||||
#ifdef SWIG_EXPORT_ITERATOR_METHODS
|
||||
%extend {
|
||||
// %extend wrapper used for differing definitions of these methods introduced in C++11
|
||||
|
|
@ -77,23 +91,33 @@
|
|||
void insert(iterator pos, size_type n, const value_type& x) { $self->insert(pos, n, x); }
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
%enddef
|
||||
|
||||
%define %std_sequence_methods_val(sequence...)
|
||||
|
||||
%std_sequence_methods_common(%arg(sequence));
|
||||
|
||||
sequence(size_type size, value_type value);
|
||||
void push_back(value_type x);
|
||||
%define %std_sequence_methods_non_resizable_val(sequence...)
|
||||
|
||||
%std_container_methods_non_resizable(%arg(sequence))
|
||||
|
||||
value_type front() const;
|
||||
value_type back() const;
|
||||
|
||||
void assign(size_type n, value_type x);
|
||||
|
||||
#endif
|
||||
|
||||
%enddef
|
||||
|
||||
%define %std_sequence_methods_val(sequence...)
|
||||
|
||||
%std_sequence_methods_common(%arg(sequence));
|
||||
|
||||
sequence(size_type size, value_type value);
|
||||
void push_back(value_type x);
|
||||
|
||||
value_type front() const;
|
||||
value_type back() const;
|
||||
|
||||
void assign(size_type n, value_type x);
|
||||
void resize(size_type new_size, value_type x);
|
||||
|
||||
|
||||
#ifdef SWIG_EXPORT_ITERATOR_METHODS
|
||||
%extend {
|
||||
// %extend wrapper used for differing definitions of these methods introduced in C++11
|
||||
|
|
@ -101,7 +125,7 @@
|
|||
void insert(iterator pos, size_type n, value_type x) { $self->insert(pos, n, x); }
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
%enddef
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -359,6 +359,7 @@ static int NAME(TYPE x) {
|
|||
%define SWIG_TYPECHECK_STDSTRING 135 %enddef
|
||||
%define SWIG_TYPECHECK_STRING 140 %enddef
|
||||
%define SWIG_TYPECHECK_PAIR 150 %enddef
|
||||
%define SWIG_TYPECHECK_STDARRAY 155 %enddef
|
||||
%define SWIG_TYPECHECK_VECTOR 160 %enddef
|
||||
%define SWIG_TYPECHECK_DEQUE 170 %enddef
|
||||
%define SWIG_TYPECHECK_LIST 180 %enddef
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue