diff --git a/Examples/test-suite/cpp11_li_std_array.i b/Examples/test-suite/cpp11_li_std_array.i index cda2198ac..e8e50105f 100644 --- a/Examples/test-suite/cpp11_li_std_array.i +++ b/Examples/test-suite/cpp11_li_std_array.i @@ -1,6 +1,6 @@ %module cpp11_li_std_array -#if defined(SWIGPYTHON) +#if defined(SWIGPYTHON) || defined(SWIGRUBY) %include diff --git a/Examples/test-suite/ruby/cpp11_li_std_array_runme.rb b/Examples/test-suite/ruby/cpp11_li_std_array_runme.rb new file mode 100644 index 000000000..41906f594 --- /dev/null +++ b/Examples/test-suite/ruby/cpp11_li_std_array_runme.rb @@ -0,0 +1,127 @@ +#!/usr/bin/env ruby +# +# Put description here +# +# +# +# +# + +require 'swig_assert' + +require 'cpp11_li_std_array' + +include Cpp11_li_std_array + + +def failed(a, b, msg) + raise RuntimeError, "#{msg} #{a} #{b}" +end + +def compare_sequences(a, b) + 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 +end + +def compare_containers(rubyarray, swigarray) + compare_sequences(rubyarray, swigarray) +end + +def setslice_exception(swigarray, newval) + begin + swigarray[0..swigarray.size] = newval + raise RuntimeError, "swigarray[] = #{newval} missed set exception for swigarray: #{swigarray}" + rescue ArgumentError => e +# print "exception: #{e}" + end +end + + +# Check std::array has similar behaviour to a Ruby array +# except it is not resizable + +ps = [0, 1, 2, 3, 4, 5] + +ai = ArrayInt6.new(ps) + +compare_containers(ps, ai) + +# slices +compare_containers(ps[0..5], ai[0..5]) +compare_containers(ps[-6..-1], ai[-6..-1]) +compare_containers(ps[0..10], ai[0..10]) + +# Reverse (.reverse is not provided) +rev = [] +ai.reverse_each { |i| rev.push i } +compare_containers(ps.reverse, rev) + +# Modify content +for i in 0..ps.size-1 + ps[i] = ps[i] * 10 + ai[i] = ai[i] * 10 +end +compare_containers(ps, ai) + +# Empty +ai = ArrayInt6.new() +compare_containers([0, 0, 0, 0, 0, 0], ai) + +# Set slice +#newvals = [10, 20, 30, 40, 50, 60] +#ai[0..5] = newvals +#compare_containers(ai, newvals) + +#newvals = [10000, 20000, 30000, 40000, 50000, 60000] +#ai[0..100] = newvals +#compare_containers(ai, newvals[0..100]) + +setslice_exception(ai, [1, 2, 3, 4, 5, 6, 7]) +setslice_exception(ai, [1, 2, 3, 4, 5]) +setslice_exception(ai, [1, 2, 3, 4]) +setslice_exception(ai, [1, 2, 3]) +setslice_exception(ai, [1, 2]) +setslice_exception(ai, [1]) +setslice_exception(ai, []) + +# Check return +compare_containers(arrayOutVal(), [-2, -1, 0, 0, 1, 2]) +compare_containers(arrayOutRef(), [-2, -1, 0, 0, 1, 2]) +compare_containers(arrayOutPtr(), [-2, -1, 0, 0, 1, 2]) + +# Check passing arguments +ai = arrayInVal([9, 8, 7, 6, 5, 4]) +compare_containers(ai, [90, 80, 70, 60, 50, 40]) + +ai = arrayInConstRef([9, 8, 7, 6, 5, 4]) +compare_containers(ai, [90, 80, 70, 60, 50, 40]) + +ai = ArrayInt6.new([9, 8, 7, 6, 5, 4]) +arrayInRef(ai) +compare_containers(ai, [90, 80, 70, 60, 50, 40]) + +ai = ArrayInt6.new([9, 8, 7, 6, 5, 4]) +arrayInPtr(ai) +compare_containers(ai, [90, 80, 70, 60, 50, 40]) + +# fill +ai.fill(111) +compare_containers(ai, [111, 111, 111, 111, 111, 111]) + +# various +ai = ArrayInt6.new([9, 8, 7, 6, 5, 4]) +swig_assert(ai.include? 9) +swig_assert(!ai.include?(99)) +swig_assert(ai.kind_of? ArrayInt6) +swig_assert(ai.find {|x| x == 6 } == 6) +swig_assert(ai.find {|x| x == 66 } == nil) +swig_assert(ai.respond_to?(:each)) +swig_assert(ai.respond_to?(:each_with_index)) + +ai = [0, 10, 20, 30, 40, 50] +ai.each_with_index { |e,i| swig_assert(e/10 == i) } + diff --git a/Lib/ruby/rubycontainer.swg b/Lib/ruby/rubycontainer.swg index 69db367d9..f8bb76e42 100644 --- a/Lib/ruby/rubycontainer.swg +++ b/Lib/ruby/rubycontainer.swg @@ -91,6 +91,12 @@ namespace swig { return pos; } + template + inline void + resize(Sequence *seq, typename Sequence::size_type n, typename Sequence::value_type x) { + seq->resize(n, x); + } + template inline Sequence* getslice(const Sequence* self, Difference i, Difference j) { @@ -164,7 +170,6 @@ namespace swig * of an element of a Ruby Array of stuff. * It can be used by RubySequence_InputIterator to make it work with STL * algorithms. - * */ template struct RubySequence_Ref @@ -210,7 +215,6 @@ namespace swig * RubySequence_Ref. * It can be used by RubySequence_InputIterator to make it work with STL * algorithms. - * */ template struct RubySequence_ArrowProxy @@ -225,7 +229,6 @@ namespace swig /** * Input Iterator. This adapator class is a random access iterator that * allows you to use STL algorithms with a Ruby class (a Ruby Array by default). - * */ template > struct RubySequence_InputIterator @@ -326,7 +329,6 @@ namespace swig /** * This adaptor class allows you to use a Ruby Array as if it was an STL * container, giving it begin(), end(), and iterators. - * */ template struct RubySequence_Cont @@ -419,7 +421,6 @@ namespace swig /** * Macros used to typemap an STL iterator -> SWIGIterator conversion. - * */ %define %swig_sequence_iterator(Sequence...) #if defined(SWIG_EXPORT_ITERATOR_METHODS) @@ -549,7 +550,6 @@ namespace swig /** * Macro used to define common Ruby printing methods for STL container - * */ %define %swig_sequence_printing_methods(Sequence...) @@ -609,9 +609,8 @@ namespace swig /** * Macro used to add common methods to all STL sequence-type containers - * */ -%define %swig_sequence_methods_common(Sequence...) +%define %swig_sequence_methods_non_resizable_common(Sequence...) %swig_container_methods(%arg(Sequence)) %swig_sequence_iterator(%arg(Sequence)) %swig_sequence_printing_methods(%arg(Sequence)) @@ -620,8 +619,7 @@ namespace swig %extend { - - VALUE slice( difference_type i, difference_type j ) + VALUE slice( difference_type i, difference_type j ) throw (std::invalid_argument) { if ( j <= 0 ) return Qnil; std::size_t len = $self->size(); @@ -657,12 +655,23 @@ namespace swig return self; } + VALUE __delete2__(const value_type& i) { + VALUE r = Qnil; + return r; + } + + } +%enddef + +%define %swig_sequence_methods_resizable_common(Sequence...) + %extend { + %newobject select; Sequence* select() { if ( !rb_block_given_p() ) rb_raise( rb_eArgError, "no block given" ); - Sequence* r = new Sequence; + Sequence* r = new Sequence(); Sequence::const_iterator i = $self->begin(); Sequence::const_iterator e = $self->end(); for ( ; i != e; ++i ) @@ -687,21 +696,17 @@ namespace swig } return r; } - - - VALUE __delete2__(const value_type& i) { - VALUE r = Qnil; - return r; - } - } %enddef +%define %swig_sequence_methods_common(Sequence...) + %swig_sequence_methods_non_resizable_common(%arg(Sequence)) + %swig_sequence_methods_resizable_common(%arg(Sequence)) +%enddef /** * Macro used to add functions for back insertion of values in - * STL Sequence containers - * + * STL sequence containers */ %define %swig_sequence_back_inserters( Sequence... ) %extend { @@ -724,7 +729,7 @@ namespace swig if ( !rb_block_given_p() ) rb_raise( rb_eArgError, "no block given" ); - Sequence* r = new Sequence; + Sequence* r = new Sequence(); std::remove_copy_if( $self->begin(), $self->end(), std::back_inserter(*r), swig::yield< Sequence::value_type >() ); @@ -748,15 +753,7 @@ namespace swig } %enddef -/** - * Macro used to add functions for Sequences - * - */ -%define %swig_sequence_methods(Sequence...) - %swig_sequence_methods_common(%arg(Sequence)); - %swig_sequence_methods_extra(%arg(Sequence)); - %swig_sequence_back_inserters(%arg(Sequence)); - +%define %swig_sequence_methods_non_resizable_accessors(Sequence...) %extend { VALUE at(difference_type i) const { @@ -770,7 +767,7 @@ namespace swig return r; } - VALUE __getitem__(difference_type i, difference_type j) const { + VALUE __getitem__(difference_type i, difference_type j) const throw (std::invalid_argument) { if ( j <= 0 ) return Qnil; std::size_t len = $self->size(); if ( i < 0 ) i = len - i; @@ -797,7 +794,7 @@ namespace swig return r; } - VALUE __getitem__(VALUE i) const { + VALUE __getitem__(VALUE i) const throw (std::invalid_argument) { if ( rb_obj_is_kind_of( i, rb_cRange ) == Qfalse ) { rb_raise( rb_eTypeError, "not a valid index or range" ); @@ -828,27 +825,27 @@ namespace swig return swig::from< Sequence* >( swig::getslice(self, s, e+1) ); } - VALUE __setitem__(difference_type i, const value_type& x) + VALUE __setitem__(difference_type i, const value_type& x) throw (std::invalid_argument) { std::size_t len = $self->size(); if ( i < 0 ) i = len - i; else if ( static_cast(i) >= len ) - $self->resize( i+1, x ); + swig::resize( $self, i+1, x ); else *(swig::getpos(self,i)) = x; return swig::from< Sequence::value_type >( x ); } - VALUE __setitem__(difference_type i, difference_type j, const Sequence& v) - throw (std::invalid_argument) { + VALUE __setitem__(difference_type i, difference_type j, const Sequence& v) throw (std::invalid_argument) + { if ( j <= 0 ) return Qnil; std::size_t len = $self->size(); if ( i < 0 ) i = len - i; j += i; if ( static_cast(j) >= len ) { - $self->resize( j+1, *(v.begin()) ); + swig::resize( $self, j+1, *(v.begin()) ); j = len-1; } @@ -857,10 +854,33 @@ namespace swig r = swig::from< const Sequence* >( &v ); return r; } - } %enddef +/** + * Macro used to add functions for non resizable sequences + */ +%define %swig_sequence_methods_non_resizable(Sequence...) + %swig_sequence_methods_non_resizable_common(%arg(Sequence)) + %swig_sequence_methods_non_resizable_accessors(%arg(Sequence)) +%enddef + + +/** + * Macro used to add functions for sequences + */ +%define %swig_sequence_methods(Sequence...) + %swig_sequence_methods_non_resizable_common(%arg(Sequence)) + %swig_sequence_methods_resizable_common(%arg(Sequence)) + %swig_sequence_methods_non_resizable_accessors(%arg(Sequence)) + %swig_sequence_methods_extra(%arg(Sequence)); + %swig_sequence_back_inserters(%arg(Sequence)); +%enddef + +%define %swig_sequence_methods_non_resizable_val(Sequence...) + %swig_sequence_methods_non_resizable(%arg(Sequence)) +%enddef + %define %swig_sequence_methods_val(Sequence...) %swig_sequence_methods(%arg(Sequence)) %enddef @@ -869,10 +889,8 @@ namespace swig /** * Macro used to add functions for front insertion of * elements in STL sequence containers that support it. - * */ %define %swig_sequence_front_inserters( Sequence... ) - %extend { VALUE shift() @@ -952,7 +970,6 @@ namespace swig return $self; } - } %enddef diff --git a/Lib/ruby/std_array.i b/Lib/ruby/std_array.i new file mode 100644 index 000000000..51ea09ba6 --- /dev/null +++ b/Lib/ruby/std_array.i @@ -0,0 +1,103 @@ +/* + std::array +*/ + +%fragment("StdArrayTraits","header",fragment="StdSequenceTraits") +%{ + namespace swig { + template + struct traits_asptr > { + static int asptr(VALUE obj, std::array **vec) { + return traits_asptr_stdseq >::asptr(obj, vec); + } + }; + + template + struct traits_from > { + static VALUE from(const std::array& vec) { + return traits_from_stdseq >::from(vec); + } + }; + + template + inline void + assign(const RubySeq& rubyseq, std::array* seq) { + if (rubyseq.size() < seq->size()) + throw std::invalid_argument("std::array cannot be expanded in size"); + else if (rubyseq.size() > seq->size()) + throw std::invalid_argument("std::array cannot be reduced in size"); + std::copy(rubyseq.begin(), rubyseq.end(), seq->begin()); + } + + template + inline void + resize(std::array *seq, typename std::array::size_type n, typename std::array::value_type x) { + throw std::invalid_argument("std::array is a fixed size container and does not support resizing"); + } + + // Only limited slicing is supported as std::array is fixed in size + template + inline std::array* + getslice(const std::array* self, Difference i, Difference j) { + using Sequence = std::array; + typename Sequence::size_type size = self->size(); + typename Sequence::size_type ii = swig::check_index(i, size); + typename Sequence::size_type jj = swig::slice_index(j, size); + + if (ii == 0 && jj == size) { + Sequence *sequence = new Sequence(); + std::copy(self->begin(), self->end(), 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 + inline void + setslice(std::array* self, Difference i, Difference j, const InputSeq& v) { + using Sequence = std::array; + typename Sequence::size_type size = self->size(); + typename Sequence::size_type ii = swig::check_index(i, size, true); + typename Sequence::size_type jj = swig::slice_index(j, size); + +std::cout << "setslice " << v[0] << " " << v[1] << std::endl; + if (ii == 0 && jj == size) { + std::copy(v.begin(), v.end(), self->begin()); + } else { + throw std::invalid_argument("std::array object only supports setting a slice that is the size of the array"); + } + } + + template + inline void + delslice(std::array* self, Difference i, Difference j) { + throw std::invalid_argument("std::array object does not support item deletion"); + } + } +%} + + +%define %swig_array_methods(Type...) + %swig_sequence_methods_non_resizable(Type) +%enddef + +%define %swig_array_methods_val(Type...) + %swig_sequence_methods_non_resizable_val(Type); +%enddef + + +%mixin std::array "Enumerable"; +%ignore std::array::push_back; +%ignore std::array::pop_back; + + +%rename("delete") std::array::__delete__; +%rename("reject!") std::array::reject_bang; +%rename("map!") std::array::map_bang; +%rename("empty?") std::array::empty; +%rename("include?" ) std::array::__contains__ const; +%rename("has_key?" ) std::array::has_key const; + +%include +