Add support for slicing steps to Python STL wrappers (positive step only atm - these work the same as other Python sequences such as list)
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@12898 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
459e083b3d
commit
1b47ddf8f0
4 changed files with 178 additions and 47 deletions
|
|
@ -5,6 +5,45 @@ See the RELEASENOTES file for a summary of changes in each release.
|
||||||
Version 2.0.5 (in progress)
|
Version 2.0.5 (in progress)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
2012-01-20: wsfulton
|
||||||
|
[Python] Add Python stepped slicing support to the STL wrappers (std::vector, std::list).
|
||||||
|
Assigning to a slice, reading a slice and deleting a slice with steps now work.
|
||||||
|
Positive steps only at the moment. For example:
|
||||||
|
|
||||||
|
%template(vector_i) std::vector<int>
|
||||||
|
|
||||||
|
vi = vector_i(range(10))
|
||||||
|
print list(vi)
|
||||||
|
vi[1:4:2] = [111, 333]
|
||||||
|
print list(vi)
|
||||||
|
del vi[3:10:3]
|
||||||
|
print list(vi)
|
||||||
|
|
||||||
|
gives (same behaviour as native Python sequences such as list):
|
||||||
|
|
||||||
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
[0, 111, 2, 333, 4, 5, 6, 7, 8, 9]
|
||||||
|
[0, 111, 2, 4, 5, 7, 8]
|
||||||
|
|
||||||
|
|
||||||
|
2012-01-20: wsfulton
|
||||||
|
[Python] Fix some indexing bugs in Python STL wrappers when the index is negative, eg:
|
||||||
|
|
||||||
|
%template(vector_i) std::vector<int>
|
||||||
|
|
||||||
|
iv=vector_i([0,1,2,3,4,5])
|
||||||
|
iv[-7:]
|
||||||
|
|
||||||
|
now returns [0, 1, 2, 3, 4, 5] instead of [5].
|
||||||
|
|
||||||
|
vv[7:9] = [22,33]
|
||||||
|
|
||||||
|
now returns [0, 1, 2, 3, 4, 5, 22, 33] instead of "index out range" error.
|
||||||
|
|
||||||
|
Also fix some segfaults when replacing ranges, eg when il is a std::list wrapper:
|
||||||
|
|
||||||
|
il[0:2] = [11]
|
||||||
|
|
||||||
2012-01-17: wsfulton
|
2012-01-17: wsfulton
|
||||||
[Go] Fix forward class declaration within a class when used as a base.
|
[Go] Fix forward class declaration within a class when used as a base.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -465,6 +465,7 @@ CPP_STD_TEST_CASES += \
|
||||||
director_string \
|
director_string \
|
||||||
ignore_template_constructor \
|
ignore_template_constructor \
|
||||||
li_std_combinations \
|
li_std_combinations \
|
||||||
|
li_std_containers_int \
|
||||||
li_std_deque \
|
li_std_deque \
|
||||||
li_std_except \
|
li_std_except \
|
||||||
li_std_map \
|
li_std_map \
|
||||||
|
|
|
||||||
12
Examples/test-suite/li_std_containers_int.i
Normal file
12
Examples/test-suite/li_std_containers_int.i
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
%module li_std_containers_int
|
||||||
|
|
||||||
|
//
|
||||||
|
// Test containers of type int
|
||||||
|
//
|
||||||
|
|
||||||
|
%include std_vector.i
|
||||||
|
%include std_list.i
|
||||||
|
|
||||||
|
%template(vector_int) std::vector<int>;
|
||||||
|
%template(list_int) std::list<int>;
|
||||||
|
|
||||||
|
|
@ -198,23 +198,28 @@ namespace swig {
|
||||||
} else if (insert && ((size_t) i == size)) {
|
} else if (insert && ((size_t) i == size)) {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::out_of_range("index out of range");
|
throw std::out_of_range("index out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
void
|
||||||
slice_index(ptrdiff_t i, size_t size) {
|
slice_adjust(ptrdiff_t i, ptrdiff_t j, ptrdiff_t step, size_t size, size_t &ii, size_t &jj, bool insert = false) {
|
||||||
if ( i < 0 ) {
|
if ( i < 0 ) {
|
||||||
if ((size_t) (-i) <= size) {
|
ii = 0;
|
||||||
return (size_t) (i + size);
|
} else if ( (size_t) i < size ) {
|
||||||
} else {
|
ii = (size_t) i;
|
||||||
throw std::out_of_range("index out of range");
|
} else if (insert && ((size_t) i >= size)) {
|
||||||
}
|
ii = size;
|
||||||
} else {
|
} else {
|
||||||
return ( (size_t) i < size ) ? ((size_t) i) : size;
|
throw std::out_of_range("index out of range");
|
||||||
|
}
|
||||||
|
if ( j < 0 ) {
|
||||||
|
jj = 0;
|
||||||
|
} else {
|
||||||
|
jj = ( (size_t) j < size ) ? ((size_t) j) : size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Sequence, class Difference>
|
template <class Sequence, class Difference>
|
||||||
inline typename Sequence::iterator
|
inline typename Sequence::iterator
|
||||||
getpos(Sequence* self, Difference i) {
|
getpos(Sequence* self, Difference i) {
|
||||||
|
|
@ -233,17 +238,35 @@ namespace swig {
|
||||||
|
|
||||||
template <class Sequence, class Difference>
|
template <class Sequence, class Difference>
|
||||||
inline Sequence*
|
inline Sequence*
|
||||||
getslice(const Sequence* self, Difference i, Difference j) {
|
getslice(const Sequence* self, Difference i, Difference j, Py_ssize_t step) {
|
||||||
|
if (step == 0)
|
||||||
|
throw std::invalid_argument("slice step cannot be zero");
|
||||||
|
|
||||||
|
if (step < 0)
|
||||||
|
throw std::invalid_argument("negative steps not implemented");
|
||||||
|
|
||||||
typename Sequence::size_type size = self->size();
|
typename Sequence::size_type size = self->size();
|
||||||
typename Sequence::size_type ii = swig::check_index(i, size);
|
typename Sequence::size_type ii = 0;
|
||||||
typename Sequence::size_type jj = swig::slice_index(j, size);
|
typename Sequence::size_type jj = 0;
|
||||||
|
swig::slice_adjust(i, j, step, size, ii, jj);
|
||||||
|
|
||||||
if (jj > ii) {
|
if (jj > ii) {
|
||||||
typename Sequence::const_iterator vb = self->begin();
|
typename Sequence::const_iterator sb = self->begin();
|
||||||
typename Sequence::const_iterator ve = self->begin();
|
typename Sequence::const_iterator se = self->begin();
|
||||||
std::advance(vb,ii);
|
std::advance(sb,ii);
|
||||||
std::advance(ve,jj);
|
std::advance(se,jj);
|
||||||
return new Sequence(vb, ve);
|
if (step == 1) {
|
||||||
|
return new Sequence(sb, se);
|
||||||
|
} else {
|
||||||
|
typename Sequence::const_iterator it = sb;
|
||||||
|
Sequence *sequence = new Sequence();
|
||||||
|
while (it!=se) {
|
||||||
|
sequence->push_back(*it);
|
||||||
|
for (typename Sequence::size_type c=0; c<step && it!=se; ++c)
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return new Sequence();
|
return new Sequence();
|
||||||
}
|
}
|
||||||
|
|
@ -251,40 +274,90 @@ namespace swig {
|
||||||
|
|
||||||
template <class Sequence, class Difference, class InputSeq>
|
template <class Sequence, class Difference, class InputSeq>
|
||||||
inline void
|
inline void
|
||||||
setslice(Sequence* self, Difference i, Difference j, const InputSeq& v = InputSeq()) {
|
setslice(Sequence* self, Difference i, Difference j, Py_ssize_t step, const InputSeq& is = InputSeq()) {
|
||||||
|
if (step == 0)
|
||||||
|
throw std::invalid_argument("slice step cannot be zero");
|
||||||
|
|
||||||
|
if (step < 0)
|
||||||
|
throw std::invalid_argument("negative steps not implemented");
|
||||||
|
|
||||||
typename Sequence::size_type size = self->size();
|
typename Sequence::size_type size = self->size();
|
||||||
typename Sequence::size_type ii = swig::check_index(i, size, true);
|
typename Sequence::size_type ii = 0;
|
||||||
typename Sequence::size_type jj = swig::slice_index(j, size);
|
typename Sequence::size_type jj = 0;
|
||||||
if (jj < ii) jj = ii;
|
swig::slice_adjust(i, j, step, size, ii, jj, true);
|
||||||
size_t ssize = jj - ii;
|
if (jj < ii)
|
||||||
if (ssize <= v.size()) {
|
jj = ii;
|
||||||
typename Sequence::iterator sb = self->begin();
|
if (step == 1) {
|
||||||
typename InputSeq::const_iterator vmid = v.begin();
|
size_t ssize = jj - ii;
|
||||||
std::advance(sb,ii);
|
if (ssize <= is.size()) {
|
||||||
std::advance(vmid, jj - ii);
|
// expanding/staying the same size
|
||||||
self->insert(std::copy(v.begin(), vmid, sb), vmid, v.end());
|
typename Sequence::iterator sb = self->begin();
|
||||||
|
typename InputSeq::const_iterator isit = is.begin();
|
||||||
|
std::advance(sb,ii);
|
||||||
|
std::advance(isit, jj - ii);
|
||||||
|
self->insert(std::copy(is.begin(), isit, sb), isit, is.end());
|
||||||
|
} else {
|
||||||
|
// shrinking
|
||||||
|
typename Sequence::iterator sb = self->begin();
|
||||||
|
typename Sequence::iterator se = self->begin();
|
||||||
|
std::advance(sb,ii);
|
||||||
|
std::advance(se,jj);
|
||||||
|
self->erase(sb,se);
|
||||||
|
sb = self->begin();
|
||||||
|
std::advance(sb,ii);
|
||||||
|
self->insert(sb, is.begin(), is.end());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
typename Sequence::iterator sb = self->begin();
|
size_t replacecount = (jj - ii + step - 1) / step;
|
||||||
typename Sequence::iterator se = self->begin();
|
if (is.size() != replacecount) {
|
||||||
std::advance(sb,ii);
|
char msg[1024];
|
||||||
std::advance(se,jj);
|
sprintf(msg, "attempt to assign sequence of size %d to extended slice of size %d", is.size(), replacecount);
|
||||||
self->erase(sb,se);
|
throw std::invalid_argument(msg);
|
||||||
self->insert(sb, v.begin(), v.end());
|
}
|
||||||
|
typename Sequence::const_iterator isit = is.begin();
|
||||||
|
typename Sequence::iterator it = self->begin();
|
||||||
|
std::advance(it,ii);
|
||||||
|
for (size_t rc=0; rc<replacecount; ++rc) {
|
||||||
|
*it++ = *isit++;
|
||||||
|
for (typename Sequence::size_type c=0; c<(step-1); ++c)
|
||||||
|
it++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Sequence, class Difference>
|
template <class Sequence, class Difference>
|
||||||
inline void
|
inline void
|
||||||
delslice(Sequence* self, Difference i, Difference j) {
|
delslice(Sequence* self, Difference i, Difference j, Py_ssize_t step) {
|
||||||
|
if (step == 0)
|
||||||
|
throw std::invalid_argument("slice step cannot be zero");
|
||||||
|
|
||||||
|
if (step < 0)
|
||||||
|
throw std::invalid_argument("negative steps not implemented");
|
||||||
|
|
||||||
typename Sequence::size_type size = self->size();
|
typename Sequence::size_type size = self->size();
|
||||||
typename Sequence::size_type ii = swig::check_index(i, size, true);
|
typename Sequence::size_type ii = 0;
|
||||||
typename Sequence::size_type jj = swig::slice_index(j, size);
|
typename Sequence::size_type jj = 0;
|
||||||
|
swig::slice_adjust(i, j, step, size, ii, jj, true);
|
||||||
if (jj > ii) {
|
if (jj > ii) {
|
||||||
typename Sequence::iterator sb = self->begin();
|
typename Sequence::iterator sb = self->begin();
|
||||||
typename Sequence::iterator se = self->begin();
|
typename Sequence::iterator se = self->begin();
|
||||||
std::advance(sb,ii);
|
std::advance(sb,ii);
|
||||||
std::advance(se,jj);
|
if (step == 1) {
|
||||||
self->erase(sb,se);
|
std::advance(se,jj);
|
||||||
|
self->erase(sb,se);
|
||||||
|
} else {
|
||||||
|
typename Sequence::iterator it = sb;
|
||||||
|
std::advance(se,jj-1);
|
||||||
|
size_t delcount = (jj - ii + step - 1) / step;
|
||||||
|
while (delcount) {
|
||||||
|
it = self->erase(it);
|
||||||
|
if (it==self->end())
|
||||||
|
break;
|
||||||
|
for (typename Sequence::size_type c=0; c<(step-1); ++c)
|
||||||
|
it++;
|
||||||
|
delcount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -607,7 +680,10 @@ namespace swig
|
||||||
|
|
||||||
%define %swig_container_methods(Container...)
|
%define %swig_container_methods(Container...)
|
||||||
|
|
||||||
|
/* deprecated in Python 2 */
|
||||||
|
#if 1
|
||||||
%newobject __getslice__;
|
%newobject __getslice__;
|
||||||
|
#endif
|
||||||
%newobject __getitem__(PySliceObject *slice);
|
%newobject __getitem__(PySliceObject *slice);
|
||||||
|
|
||||||
#if defined(SWIGPYTHON_BUILTIN)
|
#if defined(SWIGPYTHON_BUILTIN)
|
||||||
|
|
@ -669,18 +745,21 @@ namespace swig
|
||||||
$1 = PySlice_Check($input);
|
$1 = PySlice_Check($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* deprecated in Python 2 */
|
||||||
|
#if 1
|
||||||
Sequence* __getslice__(difference_type i, difference_type j) throw (std::out_of_range) {
|
Sequence* __getslice__(difference_type i, difference_type j) throw (std::out_of_range) {
|
||||||
return swig::getslice(self, i, j);
|
return swig::getslice(self, i, j, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __setslice__(difference_type i, difference_type j, const Sequence& v = Sequence())
|
void __setslice__(difference_type i, difference_type j, const Sequence& v = Sequence())
|
||||||
throw (std::out_of_range, std::invalid_argument) {
|
throw (std::out_of_range, std::invalid_argument) {
|
||||||
swig::setslice(self, i, j, v);
|
swig::setslice(self, i, j, 1, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __delslice__(difference_type i, difference_type j) throw (std::out_of_range) {
|
void __delslice__(difference_type i, difference_type j) throw (std::out_of_range) {
|
||||||
swig::delslice(self, i, j);
|
swig::delslice(self, i, j, 1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void __delitem__(difference_type i) throw (std::out_of_range) {
|
void __delitem__(difference_type i) throw (std::out_of_range) {
|
||||||
self->erase(swig::getpos(self,i));
|
self->erase(swig::getpos(self,i));
|
||||||
|
|
@ -690,14 +769,14 @@ namespace swig
|
||||||
/* Overloaded methods for Python 3 compatibility
|
/* Overloaded methods for Python 3 compatibility
|
||||||
* (Also useful in Python 2.x)
|
* (Also useful in Python 2.x)
|
||||||
*/
|
*/
|
||||||
Sequence* __getitem__(PySliceObject *slice) throw (std::out_of_range) {
|
Sequence* __getitem__(PySliceObject *slice) throw (std::out_of_range, std::invalid_argument) {
|
||||||
Py_ssize_t i, j, step;
|
Py_ssize_t i, j, step;
|
||||||
if( !PySlice_Check(slice) ) {
|
if( !PySlice_Check(slice) ) {
|
||||||
SWIG_Error(SWIG_TypeError, "Slice object expected.");
|
SWIG_Error(SWIG_TypeError, "Slice object expected.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PySlice_GetIndices(SWIGPY_SLICE_ARG(slice), self->size(), &i, &j, &step);
|
PySlice_GetIndices(SWIGPY_SLICE_ARG(slice), self->size(), &i, &j, &step);
|
||||||
return swig::getslice(self, i, j);
|
return swig::getslice(self, i, j, step);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __setitem__(PySliceObject *slice, const Sequence& v)
|
void __setitem__(PySliceObject *slice, const Sequence& v)
|
||||||
|
|
@ -708,7 +787,7 @@ namespace swig
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PySlice_GetIndices(SWIGPY_SLICE_ARG(slice), self->size(), &i, &j, &step);
|
PySlice_GetIndices(SWIGPY_SLICE_ARG(slice), self->size(), &i, &j, &step);
|
||||||
swig::setslice(self, i, j, v);
|
swig::setslice(self, i, j, step, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __setitem__(PySliceObject *slice)
|
void __setitem__(PySliceObject *slice)
|
||||||
|
|
@ -719,7 +798,7 @@ namespace swig
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PySlice_GetIndices(SWIGPY_SLICE_ARG(slice), self->size(), &i, &j, &step);
|
PySlice_GetIndices(SWIGPY_SLICE_ARG(slice), self->size(), &i, &j, &step);
|
||||||
swig::delslice(self, i,j);
|
swig::delslice(self, i, j, step);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __delitem__(PySliceObject *slice)
|
void __delitem__(PySliceObject *slice)
|
||||||
|
|
@ -730,7 +809,7 @@ namespace swig
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PySlice_GetIndices(SWIGPY_SLICE_ARG(slice), self->size(), &i, &j, &step);
|
PySlice_GetIndices(SWIGPY_SLICE_ARG(slice), self->size(), &i, &j, &step);
|
||||||
swig::delslice(self, i,j);
|
swig::delslice(self, i, j, step);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue