From: <wsf...@us...> - 2012-01-24 23:41:46
|
Revision: 12903 http://swig.svn.sourceforge.net/swig/?rev=12903&view=rev Author: wsfulton Date: 2012-01-24 23:41:40 +0000 (Tue, 24 Jan 2012) Log Message: ----------- Add support for negative steps in Python slices on the STL containers Modified Paths: -------------- trunk/CHANGES.current trunk/Examples/test-suite/python/li_std_containers_int_runme.py trunk/Lib/python/pycontainer.swg Modified: trunk/CHANGES.current =================================================================== --- trunk/CHANGES.current 2012-01-24 20:38:50 UTC (rev 12902) +++ trunk/CHANGES.current 2012-01-24 23:41:40 UTC (rev 12903) @@ -5,14 +5,10 @@ Version 2.0.5 (in progress) =========================== -2012-01-23: klickverbot - [D] Correctly annotate function pointers with C linkage. - [D] Exception and Error have become blessed names; removed d_exception_name test case. - -2012-01-20: wsfulton +2012-01-24: 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: + For example: %template(vector_i) std::vector<int> @@ -22,13 +18,18 @@ print list(vi) del vi[3:10:3] print list(vi) + print list(vi[::-1]) 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] + [8, 7, 5, 4, 2, 111, 0] +2012-01-23: klickverbot + [D] Correctly annotate function pointers with C linkage. + [D] Exception and Error have become blessed names; removed d_exception_name test case. 2012-01-20: wsfulton [Python] Fix some indexing bugs in Python STL wrappers when the index is negative, eg: Modified: trunk/Examples/test-suite/python/li_std_containers_int_runme.py =================================================================== --- trunk/Examples/test-suite/python/li_std_containers_int_runme.py 2012-01-24 20:38:50 UTC (rev 12902) +++ trunk/Examples/test-suite/python/li_std_containers_int_runme.py 2012-01-24 23:41:40 UTC (rev 12903) @@ -191,12 +191,31 @@ compare_containers(ps[-1:7:2], iv[-1:7:2], il[-1:7:2]) compare_containers(ps[-6:7:2], iv[-6:7:2], il[-6:7:2]) compare_containers(ps[-100:7:2], iv[-100:7:2], il[-100:7:2]) - compare_containers(ps[::1], iv[::1], il[::1]) compare_containers(ps[::2], iv[::2], il[::2]) -#compare_containers(ps[::-1], iv[::-1], il[]) +compare_containers(ps[::-1], iv[::-1], il[::-1]) +compare_containers(ps[6::-1], iv[6::-1], il[6::-1]) +compare_containers(ps[:-3:-1], iv[:-3:-1], il[:-3:-1]) +compare_containers(ps[:-6:-1], iv[:-6:-1], il[:-6:-1]) +compare_containers(ps[:-7:-1], iv[:-7:-1], il[:-7:-1]) +compare_containers(ps[:-8:-1], iv[:-8:-1], il[:-8:-1]) +compare_containers(ps[:-100:-1], iv[:-100:-1], il[:-100:-1]) +compare_containers(ps[4:6:-1], iv[4:6:-1], il[4:6:-1]) +compare_containers(ps[4:5:-1], iv[4:5:-1], il[4:5:-1]) +compare_containers(ps[4:4:-1], iv[4:4:-1], il[4:4:-1]) +compare_containers(ps[4:3:-1], iv[4:3:-1], il[4:3:-1]) +compare_containers(ps[4:2:-1], iv[4:2:-1], il[4:2:-1]) +compare_containers(ps[100:104:-1], iv[100:104:-1], il[100:104:-1]) +compare_containers(ps[104:100:-1], iv[104:100:-1], il[104:100:-1]) +compare_containers(ps[-100:-104:-1], iv[-100:-104:-1], il[-100:-104:-1]) +compare_containers(ps[-104:-100:-1], iv[-104:-100:-1], il[-104:-100:-1]) +compare_containers(ps[::-2], iv[::-2], il[::-2]) +compare_containers(ps[::-3], iv[::-3], il[::-3]) +compare_containers(ps[::-4], iv[::-4], il[::-4]) +compare_containers(ps[::-5], iv[::-5], il[::-5]) + # insert sequences (growing, shrinking and staying same size) for start in [-102, -100, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 100, 102]: # single element set/replace @@ -217,7 +236,7 @@ container_delete_step(start, None, None) for end in [-102, -100, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 100, 102]: container_delete_step(start, end, None) - for step in range(1,7): + for step in range(-7,7): container_delete_step(start, end, step) ps = range(6) @@ -227,7 +246,7 @@ compare_containers(ps, iv, il) for end in range(7): - for step in range(1,7): + for step in range(-7,7): for start in range(7): container_insert_step(start, end, step, [111, 222, 333, 444, 555, 666, 777]) container_insert_step(start, end, step, [111, 222, 333, 444, 555, 666]) Modified: trunk/Lib/python/pycontainer.swg =================================================================== --- trunk/Lib/python/pycontainer.swg 2012-01-24 20:38:50 UTC (rev 12902) +++ trunk/Lib/python/pycontainer.swg 2012-01-24 23:41:40 UTC (rev 12903) @@ -202,24 +202,40 @@ } void - 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 ) { - ii = 0; - } else if ( (size_t) i < size ) { - ii = (size_t) i; - } else if (insert && ((size_t) i >= size)) { - ii = size; + slice_adjust(ptrdiff_t i, ptrdiff_t j, ptrdiff_t step, size_t size, ptrdiff_t &ii, ptrdiff_t &jj, bool insert = false) { + if (step == 0) { + throw std::invalid_argument("slice step cannot be zero"); + } else if (step > 0) { + // Required range: 0 <= i < size, 0 <= j < size + if (i < 0) { + ii = 0; + } else if (i < (ptrdiff_t)size) { + ii = i; + } else if (insert && (i >= (ptrdiff_t)size)) { + ii = (ptrdiff_t)size; + } + if ( j < 0 ) { + jj = 0; + } else { + jj = (j < (ptrdiff_t)size) ? j : (ptrdiff_t)size; + } } else { - throw std::out_of_range("index out of range"); + // Required range: -1 <= i < size-1, -1 <= j < size-1 + if (i < -1) { + ii = -1; + } else if (i < (ptrdiff_t) size) { + ii = i; + } else if (i >= (ptrdiff_t)(size-1)) { + ii = (ptrdiff_t)(size-1); + } + if (j < -1) { + jj = -1; + } else { + jj = (j < (ptrdiff_t)size ) ? j : (ptrdiff_t)(size-1); + } } - if ( j < 0 ) { - jj = 0; - } else { - jj = ( (size_t) j < size ) ? ((size_t) j) : size; - } } - template <class Sequence, class Difference> inline typename Sequence::iterator getpos(Sequence* self, Difference i) { @@ -239,18 +255,12 @@ template <class Sequence, class Difference> inline Sequence* 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 ii = 0; - typename Sequence::size_type jj = 0; + Difference ii = 0; + Difference jj = 0; swig::slice_adjust(i, j, step, size, ii, jj); - if (jj > ii) { + if (step > 0) { typename Sequence::const_iterator sb = self->begin(); typename Sequence::const_iterator se = self->begin(); std::advance(sb,ii); @@ -258,68 +268,94 @@ if (step == 1) { return new Sequence(sb, se); } else { + Sequence *sequence = new Sequence(); 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 { + Sequence *sequence = new Sequence(); + if (ii > jj) { + typename Sequence::const_reverse_iterator sb = self->rbegin(); + typename Sequence::const_reverse_iterator se = self->rbegin(); + std::advance(sb,size-ii-1); + std::advance(se,size-jj-1); + typename Sequence::const_reverse_iterator it = sb; + while (it!=se) { + sequence->push_back(*it); + for (typename Sequence::size_type c=0; c<-step && it!=se; ++c) + it++; + } } - } else { - return new Sequence(); + return sequence; } } template <class Sequence, class Difference, class InputSeq> inline void 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 ii = 0; - typename Sequence::size_type jj = 0; + Difference ii = 0; + Difference jj = 0; swig::slice_adjust(i, j, step, size, ii, jj, true); - if (jj < ii) - jj = ii; - if (step == 1) { - size_t ssize = jj - ii; - if (ssize <= is.size()) { - // expanding/staying the same size - 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()); + if (step > 0) { + if (jj < ii) + jj = ii; + if (step == 1) { + size_t ssize = jj - ii; + if (ssize <= is.size()) { + // expanding/staying the same size + 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 { - // 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()); + size_t replacecount = (jj - ii + step - 1) / step; + if (is.size() != replacecount) { + char msg[1024]; + sprintf(msg, "attempt to assign sequence of size %d to extended slice of size %d", is.size(), replacecount); + throw std::invalid_argument(msg); + } + 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++; + } } } else { - size_t replacecount = (jj - ii + step - 1) / step; + if (jj > ii) + jj = ii; + size_t replacecount = (ii - jj - step - 1) / -step; if (is.size() != replacecount) { char msg[1024]; sprintf(msg, "attempt to assign sequence of size %d to extended slice of size %d", is.size(), replacecount); throw std::invalid_argument(msg); } typename Sequence::const_iterator isit = is.begin(); - typename Sequence::iterator it = self->begin(); - std::advance(it,ii); + typename Sequence::reverse_iterator it = self->rbegin(); + std::advance(it,size-ii-1); for (size_t rc=0; rc<replacecount; ++rc) { *it++ = *isit++; - for (typename Sequence::size_type c=0; c<(step-1); ++c) + for (typename Sequence::size_type c=0; c<(-step-1); ++c) it++; } } @@ -328,32 +364,42 @@ template <class Sequence, class Difference> inline void 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 ii = 0; - typename Sequence::size_type jj = 0; + Difference ii = 0; + Difference jj = 0; swig::slice_adjust(i, j, step, size, ii, jj, true); - if (jj > ii) { - typename Sequence::iterator sb = self->begin(); - typename Sequence::iterator se = self->begin(); - std::advance(sb,ii); - if (step == 1) { - 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; + if (step > 0) { + if (jj > ii) { + typename Sequence::iterator sb = self->begin(); + std::advance(sb,ii); + if (step == 1) { + typename Sequence::iterator se = self->begin(); + std::advance(se,jj); + self->erase(sb,se); + } else { + typename Sequence::iterator it = sb; + 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--; + } + } + } + } else { + if (ii > jj) { + typename Sequence::reverse_iterator sb = self->rbegin(); + std::advance(sb,size-ii-1); + typename Sequence::reverse_iterator it = sb; + size_t delcount = (ii - jj - step - 1) / -step; while (delcount) { - it = self->erase(it); - if (it==self->end()) + self->erase((++it).base()); + if (it==self->rend()) break; - for (typename Sequence::size_type c=0; c<(step-1); ++c) + for (typename Sequence::size_type c=0; c<(-step-1); ++c) it++; delcount--; } @@ -747,7 +793,7 @@ /* 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, std::invalid_argument) { return swig::getslice(self, i, j, 1); } @@ -756,7 +802,7 @@ 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, std::invalid_argument) { swig::delslice(self, i, j, 1); } #endif @@ -791,7 +837,7 @@ } void __setitem__(PySliceObject *slice) - throw (std::out_of_range) { + throw (std::out_of_range, std::invalid_argument) { Py_ssize_t i, j, step; if( !PySlice_Check(slice) ) { SWIG_Error(SWIG_TypeError, "Slice object expected."); @@ -802,7 +848,7 @@ } void __delitem__(PySliceObject *slice) - throw (std::out_of_range) { + throw (std::out_of_range, std::invalid_argument) { Py_ssize_t i, j, step; if( !PySlice_Check(slice) ) { SWIG_Error(SWIG_TypeError, "Slice object expected."); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |