Ruby STL container ranges and slices fixes.
Access via ranges and slices now behave identically to Ruby arrays. The fixes are mostly for out of range indices and lengths. - Zero length slice requests return an empty container instead of nil. - Slices which request a length greater than the size of the container no longer chop off the last element. - Ranges which used to return nil now return an empty array when the the start element is a valid index.
This commit is contained in:
parent
97b129de6c
commit
cd33aba427
3 changed files with 114 additions and 42 deletions
|
|
@ -39,12 +39,12 @@ iv.each_with_index { |e,i|
|
||||||
"iv.slice(1,2).to_s" => "12",
|
"iv.slice(1,2).to_s" => "12",
|
||||||
"iv[0,-2]" => nil,
|
"iv[0,-2]" => nil,
|
||||||
"iv[0,3].to_s" => "012",
|
"iv[0,3].to_s" => "012",
|
||||||
"iv[0,10].to_s" => "012",
|
"iv[0,10].to_s" => "0123",
|
||||||
"iv[1..2].to_s" => '12',
|
"iv[1..2].to_s" => '12',
|
||||||
"iv[1..3].to_s" => '123',
|
"iv[1..3].to_s" => '123',
|
||||||
"iv[1..4].to_s" => '123',
|
"iv[1..4].to_s" => '123',
|
||||||
"iv[1..-2].to_s" => '12',
|
"iv[1..-2].to_s" => '12',
|
||||||
"iv[2..-3]" => nil,
|
"iv[2..-3].to_s" => '',
|
||||||
}.each do |k,v|
|
}.each do |k,v|
|
||||||
swig_assert( "#{k} == #{v.inspect}", binding )
|
swig_assert( "#{k} == #{v.inspect}", binding )
|
||||||
end
|
end
|
||||||
|
|
@ -100,6 +100,66 @@ end
|
||||||
iv[6] = 5
|
iv[6] = 5
|
||||||
swig_assert_equal(iv.to_s, '6239555', binding)
|
swig_assert_equal(iv.to_s, '6239555', binding)
|
||||||
|
|
||||||
|
def failed(a, b, msg)
|
||||||
|
a = 'nil' if a == nil
|
||||||
|
b = 'nil' if b == nil
|
||||||
|
raise RuntimeError, "#{msg}: #{a} ... #{b}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def compare_sequences(a, b)
|
||||||
|
if a != nil && b != nil
|
||||||
|
if a.size != b.size
|
||||||
|
failed(a, b, "different sizes")
|
||||||
|
end
|
||||||
|
for i in 0..a.size-1
|
||||||
|
failed(a, b, "elements are different") if a[i] != b[i]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
unless a == nil && b == nil
|
||||||
|
failed(a, b, "only one of the sequences is nil")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_slice(i, length)
|
||||||
|
aa = [0,1,2,3]
|
||||||
|
iv = IntVector.new([0,1,2,3])
|
||||||
|
|
||||||
|
aa_slice = aa[i, length]
|
||||||
|
iv_slice = iv[i, length]
|
||||||
|
compare_sequences(aa_slice, iv_slice)
|
||||||
|
|
||||||
|
aa_slice = aa.slice(i, length)
|
||||||
|
iv_slice = iv.slice(i, length)
|
||||||
|
compare_sequences(aa_slice, iv_slice)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_range(i, j)
|
||||||
|
aa = [0,1,2,3]
|
||||||
|
iv = IntVector.new([0,1,2,3])
|
||||||
|
|
||||||
|
aa_range = aa[i..j]
|
||||||
|
iv_range = iv[i..j]
|
||||||
|
compare_sequences(aa_range, iv_range)
|
||||||
|
|
||||||
|
aa_range = aa[Range.new(i, j, true)]
|
||||||
|
iv_range = iv[Range.new(i, j, true)]
|
||||||
|
compare_sequences(aa_range, iv_range)
|
||||||
|
end
|
||||||
|
|
||||||
|
for i in -5..5
|
||||||
|
for length in -5..5
|
||||||
|
check_slice(i, length)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i in -5..5
|
||||||
|
for j in -5..5
|
||||||
|
check_range(i, j)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
dv = DoubleVector.new(10)
|
dv = DoubleVector.new(10)
|
||||||
|
|
||||||
swig_assert( "dv.respond_to? :each_with_index", binding )
|
swig_assert( "dv.respond_to? :each_with_index", binding )
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ namespace swig {
|
||||||
inline Sequence*
|
inline Sequence*
|
||||||
getslice(const Sequence* self, Difference i, Difference j) {
|
getslice(const Sequence* self, Difference i, Difference j) {
|
||||||
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 = (i == size && j == size) ? i : swig::check_index(i, size);
|
||||||
typename Sequence::size_type jj = swig::slice_index(j, size);
|
typename Sequence::size_type jj = swig::slice_index(j, size);
|
||||||
|
|
||||||
if (jj > ii) {
|
if (jj > ii) {
|
||||||
|
|
@ -619,20 +619,25 @@ namespace swig
|
||||||
|
|
||||||
%extend {
|
%extend {
|
||||||
|
|
||||||
VALUE slice( difference_type i, difference_type j ) throw (std::invalid_argument)
|
VALUE slice( difference_type i, difference_type length ) throw (std::invalid_argument) {
|
||||||
{
|
if ( length < 0 )
|
||||||
if ( j <= 0 ) return Qnil;
|
return Qnil;
|
||||||
std::size_t len = $self->size();
|
std::size_t len = $self->size();
|
||||||
if ( i < 0 ) i = len - i;
|
if ( i < 0 ) {
|
||||||
j += i;
|
if ( i + static_cast<Sequence::difference_type>(len) < 0 )
|
||||||
if ( static_cast<std::size_t>(j) >= len ) j = len-1;
|
return Qnil;
|
||||||
|
else
|
||||||
|
i = len + i;
|
||||||
|
}
|
||||||
|
Sequence::difference_type j = length + i;
|
||||||
|
if ( j > static_cast<Sequence::difference_type>(len) )
|
||||||
|
j = len;
|
||||||
|
|
||||||
VALUE r = Qnil;
|
VALUE r = Qnil;
|
||||||
try {
|
try {
|
||||||
r = swig::from< const Sequence* >( swig::getslice(self, i, j) );
|
r = swig::from< const Sequence* >( swig::getslice(self, i, j) );
|
||||||
}
|
}
|
||||||
catch( std::out_of_range )
|
catch( std::out_of_range ) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
@ -761,24 +766,30 @@ namespace swig
|
||||||
try {
|
try {
|
||||||
r = swig::from< Sequence::value_type >( *(swig::cgetpos(self, i)) );
|
r = swig::from< Sequence::value_type >( *(swig::cgetpos(self, i)) );
|
||||||
}
|
}
|
||||||
catch( std::out_of_range )
|
catch( std::out_of_range ) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE __getitem__(difference_type i, difference_type j) const throw (std::invalid_argument) {
|
VALUE __getitem__(difference_type i, difference_type length) const throw (std::invalid_argument) {
|
||||||
if ( j <= 0 ) return Qnil;
|
if ( length < 0 )
|
||||||
|
return Qnil;
|
||||||
std::size_t len = $self->size();
|
std::size_t len = $self->size();
|
||||||
if ( i < 0 ) i = len - i;
|
if ( i < 0 ) {
|
||||||
j += i; if ( static_cast<std::size_t>(j) >= len ) j = len-1;
|
if ( i + static_cast<Sequence::difference_type>(len) < 0 )
|
||||||
|
return Qnil;
|
||||||
|
else
|
||||||
|
i = len + i;
|
||||||
|
}
|
||||||
|
Sequence::difference_type j = length + i;
|
||||||
|
if ( j > static_cast<Sequence::difference_type>(len) )
|
||||||
|
j = len;
|
||||||
|
|
||||||
VALUE r = Qnil;
|
VALUE r = Qnil;
|
||||||
try {
|
try {
|
||||||
r = swig::from< const Sequence* >( swig::getslice(self, i, j) );
|
r = swig::from< const Sequence* >( swig::getslice(self, i, j) );
|
||||||
}
|
}
|
||||||
catch( std::out_of_range )
|
catch( std::out_of_range ) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
@ -788,15 +799,13 @@ namespace swig
|
||||||
try {
|
try {
|
||||||
r = swig::from< Sequence::value_type >( *(swig::cgetpos(self, i)) );
|
r = swig::from< Sequence::value_type >( *(swig::cgetpos(self, i)) );
|
||||||
}
|
}
|
||||||
catch( std::out_of_range )
|
catch( std::out_of_range ) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE __getitem__(VALUE i) const throw (std::invalid_argument) {
|
VALUE __getitem__(VALUE i) const throw (std::invalid_argument) {
|
||||||
if ( rb_obj_is_kind_of( i, rb_cRange ) == Qfalse )
|
if ( rb_obj_is_kind_of( i, rb_cRange ) == Qfalse ) {
|
||||||
{
|
|
||||||
rb_raise( rb_eTypeError, "not a valid index or range" );
|
rb_raise( rb_eTypeError, "not a valid index or range" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -811,16 +820,19 @@ namespace swig
|
||||||
int len = $self->size();
|
int len = $self->size();
|
||||||
|
|
||||||
int s = NUM2INT( start );
|
int s = NUM2INT( start );
|
||||||
if ( s < 0 ) s = len + s;
|
if ( s < 0 ) {
|
||||||
else if ( s >= len ) return Qnil;
|
s = len + s;
|
||||||
|
if ( s < 0 )
|
||||||
|
return Qnil;
|
||||||
|
} else if ( s > len )
|
||||||
|
return Qnil;
|
||||||
|
|
||||||
int e = NUM2INT( end );
|
int e = NUM2INT( end );
|
||||||
if ( e < 0 ) e = len + e;
|
if ( e < 0 ) e = len + e;
|
||||||
|
|
||||||
if ( e < s ) return Qnil; //std::swap( s, e );
|
|
||||||
|
|
||||||
if ( noend ) e -= 1;
|
if ( noend ) e -= 1;
|
||||||
|
if ( e < 0 ) e = -1;
|
||||||
if ( e >= len ) e = len - 1;
|
if ( e >= len ) e = len - 1;
|
||||||
|
if ( s == len ) e = len - 1;
|
||||||
|
|
||||||
return swig::from< Sequence* >( swig::getslice(self, s, e+1) );
|
return swig::from< Sequence* >( swig::getslice(self, s, e+1) );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
getslice(const std::array<T, N>* self, Difference i, Difference j) {
|
getslice(const std::array<T, N>* self, Difference i, Difference j) {
|
||||||
using Sequence = std::array<T, N>;
|
using Sequence = std::array<T, N>;
|
||||||
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 = (i == size && j == size) ? i : swig::check_index(i, size);
|
||||||
typename Sequence::size_type jj = swig::slice_index(j, size);
|
typename Sequence::size_type jj = swig::slice_index(j, size);
|
||||||
|
|
||||||
if (ii == 0 && jj == size) {
|
if (ii == 0 && jj == size) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue