Home | History | Annotate | Download | only in ruby
      1 /* -----------------------------------------------------------------------------
      2  * rubycontainer.swg
      3  *
      4  * Ruby sequence <-> C++ container wrapper
      5  *
      6  * This wrapper, and its iterator, allows a general use (and reuse) of
      7  * the mapping between C++ and Ruby, thanks to the C++ templates.
      8  *
      9  * Of course, it needs the C++ compiler to support templates, but
     10  * since we will use this wrapper with the STL containers, that should
     11  * be the case.
     12  * ----------------------------------------------------------------------------- */
     13 
     14 %{
     15 #include <iostream>
     16 %}
     17 
     18 
     19 #if !defined(SWIG_NO_EXPORT_ITERATOR_METHODS)
     20 # if !defined(SWIG_EXPORT_ITERATOR_METHODS)
     21 #  define SWIG_EXPORT_ITERATOR_METHODS SWIG_EXPORT_ITERATOR_METHODS
     22 # endif
     23 #endif
     24 
     25 %include <rubyiterators.swg>
     26 
     27 /**** The RubySequence C++ Wrap ***/
     28 
     29 %insert(header) %{
     30 #include <stdexcept>
     31 %}
     32 
     33 %include <std_except.i>
     34 
     35 
     36 %fragment("RubySequence_Base","header")
     37 {
     38 %#include <functional>
     39 
     40 
     41 namespace swig {
     42   template < class T >
     43   struct yield : public std::unary_function< T, bool >
     44   {
     45     bool
     46     operator()( const T& v ) const
     47     {
     48       return RTEST( rb_yield( swig::from< T >(v) ) );
     49     }
     50   };
     51 
     52 
     53   inline size_t
     54   check_index(ptrdiff_t i, size_t size, bool insert = false) {
     55     if ( i < 0 ) {
     56       if ((size_t) (-i) <= size)
     57 	return (size_t) (i + size);
     58     } else if ( (size_t) i < size ) {
     59       return (size_t) i;
     60     } else if (insert && ((size_t) i == size)) {
     61       return size;
     62     }
     63 
     64     throw std::out_of_range("index out of range");
     65   }
     66 
     67   inline size_t
     68   slice_index(ptrdiff_t i, size_t size) {
     69     if ( i < 0 ) {
     70       if ((size_t) (-i) <= size) {
     71 	return (size_t) (i + size);
     72       } else {
     73 	throw std::out_of_range("index out of range");
     74       }
     75     } else {
     76       return ( (size_t) i < size ) ? ((size_t) i) : size;
     77     }
     78   }
     79 
     80   template <class Sequence, class Difference>
     81   inline typename Sequence::iterator
     82   getpos(Sequence* self, Difference i)  {
     83     typename Sequence::iterator pos = self->begin();
     84     std::advance(pos, check_index(i,self->size()));
     85     return pos;
     86   }
     87 
     88   template <class Sequence, class Difference>
     89   inline typename Sequence::const_iterator
     90   cgetpos(const Sequence* self, Difference i)  {
     91     typename Sequence::const_iterator pos = self->begin();
     92     std::advance(pos, check_index(i,self->size()));
     93     return pos;
     94   }
     95 
     96   template <class Sequence, class Difference>
     97   inline Sequence*
     98   getslice(const Sequence* self, Difference i, Difference j) {
     99     typename Sequence::size_type size = self->size();
    100     typename Sequence::size_type ii = swig::check_index(i, size);
    101     typename Sequence::size_type jj = swig::slice_index(j, size);
    102 
    103     if (jj > ii) {
    104       typename Sequence::const_iterator vb = self->begin();
    105       typename Sequence::const_iterator ve = self->begin();
    106       std::advance(vb,ii);
    107       std::advance(ve,jj);
    108       return new Sequence(vb, ve);
    109     } else {
    110       return new Sequence();
    111     }
    112   }
    113 
    114   template <class Sequence, class Difference, class InputSeq>
    115   inline void
    116   setslice(Sequence* self, Difference i, Difference j, const InputSeq& v) {
    117     typename Sequence::size_type size = self->size();
    118     typename Sequence::size_type ii = swig::check_index(i, size, true);
    119     typename Sequence::size_type jj = swig::slice_index(j, size);
    120     if (jj < ii) jj = ii;
    121     size_t ssize = jj - ii;
    122     if (ssize <= v.size()) {
    123       typename Sequence::iterator sb = self->begin();
    124       typename InputSeq::const_iterator vmid = v.begin();
    125       std::advance(sb,ii);
    126       std::advance(vmid, jj - ii);
    127       self->insert(std::copy(v.begin(), vmid, sb), vmid, v.end());
    128     } else {
    129       typename Sequence::iterator sb = self->begin();
    130       typename Sequence::iterator se = self->begin();
    131       std::advance(sb,ii);
    132       std::advance(se,jj);
    133       self->erase(sb,se);
    134       self->insert(sb, v.begin(), v.end());
    135     }
    136   }
    137 
    138   template <class Sequence, class Difference>
    139   inline void
    140   delslice(Sequence* self, Difference i, Difference j) {
    141     typename Sequence::size_type size = self->size();
    142     typename Sequence::size_type ii = swig::check_index(i, size, true);
    143     typename Sequence::size_type jj = swig::slice_index(j, size);
    144     if (jj > ii) {
    145       typename Sequence::iterator sb = self->begin();
    146       typename Sequence::iterator se = self->begin();
    147       std::advance(sb,ii);
    148       std::advance(se,jj);
    149       self->erase(sb,se);
    150     }
    151   }
    152 }
    153 }
    154 
    155 %fragment("RubySequence_Cont","header",
    156 	  fragment="<stddef.h>",
    157 	  fragment="StdTraits",
    158 	  fragment="RubySequence_Base",
    159 	  fragment="ConstIterator_T")
    160 {
    161 namespace swig
    162 {
    163 
    164   /**
    165    * This class is a proxy class for references, used to return and set values
    166    * of an element of a Ruby Array of stuff.
    167    * It can be used by RubySequence_InputIterator to make it work with STL
    168    * algorithms.
    169    *
    170    */
    171   template <class T>
    172   struct RubySequence_Ref
    173   {
    174     RubySequence_Ref(VALUE  seq, int index)
    175       : _seq(seq), _index(index)
    176     {
    177     }
    178 
    179     operator T () const
    180     {
    181       VALUE item = rb_ary_entry(_seq, _index );
    182       try {
    183 	return swig::as<T>(item, true);
    184       } catch (std::exception& e) {
    185 	char msg[1024];
    186 	sprintf(msg, "in sequence element %d ", _index);
    187 	VALUE lastErr = rb_gv_get("$!");
    188 	if ( lastErr == Qnil ) {
    189 	  %type_error(swig::type_name<T>());
    190 	}
    191 	VALUE str = rb_str_new2(msg);
    192 	str = rb_str_cat2( str, e.what() );
    193 	SWIG_Ruby_ExceptionType( NULL, str );
    194 	throw;
    195       }
    196     }
    197 
    198     RubySequence_Ref& operator=(const T& v)
    199     {
    200       rb_ary_set(_seq, _index, swig::from< T >(v));
    201       return *this;
    202     }
    203 
    204   private:
    205     VALUE  _seq;
    206     int _index;
    207   };
    208 
    209 
    210   /**
    211    * This class is a proxy to return a pointer to a class, usually
    212    * RubySequence_Ref.
    213    * It can be used by RubySequence_InputIterator to make it work with STL
    214    * algorithms.
    215    *
    216    */
    217   template <class T>
    218   struct RubySequence_ArrowProxy
    219   {
    220     RubySequence_ArrowProxy(const T& x): m_value(x) {}
    221     const T* operator->() const { return &m_value; }
    222     operator const T*() const { return &m_value; }
    223     T m_value;
    224   };
    225 
    226 
    227   /**
    228    * Input Iterator.  This adapator class is a random access iterator that
    229    * allows you to use STL algorithms with a Ruby class (a Ruby Array by default).
    230    *
    231    */
    232   template <class T, class Reference = RubySequence_Ref< T > >
    233   struct RubySequence_InputIterator
    234   {
    235     typedef RubySequence_InputIterator<T, Reference > self;
    236 
    237     typedef std::random_access_iterator_tag iterator_category;
    238     typedef Reference reference;
    239     typedef T value_type;
    240     typedef T* pointer;
    241     typedef ptrdiff_t difference_type;
    242 
    243     RubySequence_InputIterator()
    244     {
    245     }
    246 
    247     RubySequence_InputIterator(VALUE  seq, int index)
    248       : _seq(seq), _index(index)
    249     {
    250     }
    251 
    252     reference operator*() const
    253     {
    254       return reference(_seq, _index);
    255     }
    256 
    257     RubySequence_ArrowProxy<T>
    258     operator->() const {
    259       return RubySequence_ArrowProxy<T>(operator*());
    260     }
    261 
    262     bool operator==(const self& ri) const
    263     {
    264       return (_index == ri._index) && (_seq == ri._seq);
    265     }
    266 
    267     bool operator!=(const self& ri) const
    268     {
    269       return !(operator==(ri));
    270     }
    271 
    272     self& operator ++ ()
    273     {
    274       ++_index;
    275       return *this;
    276     }
    277 
    278     self& operator -- ()
    279     {
    280       --_index;
    281       return *this;
    282     }
    283 
    284     self& operator += (difference_type n)
    285     {
    286       _index += n;
    287       return *this;
    288     }
    289 
    290     self operator +(difference_type n) const
    291     {
    292       return self(_seq, _index + n);
    293     }
    294 
    295     self& operator -= (difference_type n)
    296     {
    297       _index -= n;
    298       return *this;
    299     }
    300 
    301     self operator -(difference_type n) const
    302     {
    303       return self(_seq, _index - n);
    304     }
    305 
    306     difference_type operator - (const self& ri) const
    307     {
    308       return _index - ri._index;
    309     }
    310 
    311     bool operator < (const self& ri) const
    312     {
    313       return _index < ri._index;
    314     }
    315 
    316     reference
    317     operator[](difference_type n) const
    318     {
    319       return reference(_seq, _index + n);
    320     }
    321 
    322   private:
    323     VALUE  _seq;
    324     difference_type _index;
    325   };
    326 
    327 
    328   /**
    329    * This adaptor class allows you to use a Ruby Array as if it was an STL
    330    * container, giving it begin(), end(), and iterators.
    331    *
    332    */
    333   template <class T>
    334   struct RubySequence_Cont
    335   {
    336     typedef RubySequence_Ref<T> reference;
    337     typedef const RubySequence_Ref<T> const_reference;
    338     typedef T value_type;
    339     typedef T* pointer;
    340     typedef int difference_type;
    341     typedef int size_type;
    342     typedef const pointer const_pointer;
    343     typedef RubySequence_InputIterator<T, reference> iterator;
    344     typedef RubySequence_InputIterator<T, const_reference> const_iterator;
    345 
    346     RubySequence_Cont(VALUE  seq) : _seq(0)
    347     {
    348       if (!rb_obj_is_kind_of(seq, rb_cArray)) {
    349 	throw std::invalid_argument("an Array is expected");
    350       }
    351       _seq = seq;
    352     }
    353 
    354     ~RubySequence_Cont()
    355     {
    356     }
    357 
    358     size_type size() const
    359     {
    360       return RARRAY_LEN(_seq);
    361     }
    362 
    363     bool empty() const
    364     {
    365       return size() == 0;
    366     }
    367 
    368     iterator begin()
    369     {
    370       return iterator(_seq, 0);
    371     }
    372 
    373     const_iterator begin() const
    374     {
    375       return const_iterator(_seq, 0);
    376     }
    377 
    378     iterator end()
    379     {
    380       return iterator(_seq, size());
    381     }
    382 
    383     const_iterator end() const
    384     {
    385       return const_iterator(_seq, size());
    386     }
    387 
    388     reference operator[](difference_type n)
    389     {
    390       return reference(_seq, n);
    391     }
    392 
    393     const_reference operator[](difference_type n)  const
    394     {
    395       return const_reference(_seq, n);
    396     }
    397 
    398     bool check(bool set_err = false) const
    399     {
    400       int s = (int) size();
    401       for (int i = 0; i < s; ++i) {
    402 	VALUE item = rb_ary_entry(_seq, i );
    403 	if (!swig::check<value_type>(item)) {
    404 	  if (set_err) {
    405 	    char msg[1024];
    406 	    sprintf(msg, "in sequence element %d", i);
    407 	    SWIG_Error(SWIG_RuntimeError, msg);
    408 	  }
    409 	  return false;
    410 	}
    411       }
    412       return true;
    413     }
    414 
    415   private:
    416     VALUE  _seq;
    417   };
    418 
    419 }
    420 }
    421 
    422 /**
    423  * Macros used to typemap an STL iterator -> SWIGIterator conversion.
    424  *
    425  */
    426 %define %swig_sequence_iterator(Sequence...)
    427 #if defined(SWIG_EXPORT_ITERATOR_METHODS)
    428 
    429   %typemap(out,noblock=1,fragment="RubySequence_Cont")
    430     const_iterator, const_reverse_iterator {
    431     $result = SWIG_NewPointerObj(swig::make_const_iterator(%static_cast($1,const $type &),
    432 							   self),
    433 				 swig::ConstIterator::descriptor(),SWIG_POINTER_OWN);
    434   }
    435 
    436   %typemap(out,noblock=1,fragment="RubySequence_Cont")
    437     iterator, reverse_iterator {
    438     $result = SWIG_NewPointerObj(swig::make_nonconst_iterator(%static_cast($1,const $type &),
    439 							      self),
    440 				 swig::Iterator::descriptor(),SWIG_POINTER_OWN);
    441   }
    442 
    443   %typemap(out,noblock=1,fragment="RubySequence_Cont")
    444     std::pair<const_iterator, const_iterator> {
    445     $result = rb_ary_new2(2);
    446     rb_ary_push($result, SWIG_NewPointerObj(swig::make_const_iterator(%static_cast($1,const $type &).first),
    447 					    swig::ConstIterator::descriptor(),SWIG_POINTER_OWN));
    448     rb_ary_push($result, SWIG_NewPointerObj(swig::make_const_iterator(%static_cast($1,const $type &).second),
    449 					    swig::ConstIterator::descriptor(),SWIG_POINTER_OWN));
    450   }
    451 
    452   // std::map/multimap/set allow returning std::pair< iterator, iterator > from
    453   // equal_range, but we cannot still modify the key, so the iterator is
    454   // const.
    455   %typemap(out,noblock=1,fragment="RubySequence_Cont")
    456     std::pair<iterator, iterator> {
    457     $result = rb_ary_new2(2);
    458     rb_ary_push($result, SWIG_NewPointerObj(swig::make_const_iterator(%static_cast($1,const $type &).first),
    459 					    swig::ConstIterator::descriptor(),SWIG_POINTER_OWN));
    460     rb_ary_push($result, SWIG_NewPointerObj(swig::make_const_iterator(%static_cast($1,const $type &).second),
    461 					    swig::ConstIterator::descriptor(),SWIG_POINTER_OWN));
    462   }
    463 
    464 
    465   %typemap(in,noblock=1,fragment="RubySequence_Cont")
    466     const_iterator(swig::ConstIterator *iter = 0, int res),
    467     const_reverse_iterator(swig::ConstIterator *iter = 0, int res) {
    468     res = SWIG_ConvertPtr($input, %as_voidptrptr(&iter),
    469 			  swig::ConstIterator::descriptor(), 0);
    470     if (!SWIG_IsOK(res) || !iter) {
    471       %argument_fail(SWIG_TypeError, "$type", $symname, $argnum);
    472     } else {
    473       swig::ConstIterator_T<$type > *iter_t = dynamic_cast<swig::ConstIterator_T<$type > *>(iter);
    474       if (iter_t) {
    475 	$1 = iter_t->get_current();
    476       } else {
    477 	%argument_fail(SWIG_TypeError, "$type", $symname, $argnum);
    478       }
    479     }
    480   }
    481 
    482   %typemap(in,noblock=1,fragment="RubySequence_Cont")
    483     iterator(swig::Iterator *iter = 0, int res),
    484     reverse_iterator(swig::Iterator *iter = 0, int res) {
    485     res = SWIG_ConvertPtr($input, %as_voidptrptr(&iter), swig::Iterator::descriptor(), 0);
    486     if (!SWIG_IsOK(res) || !iter) {
    487       %argument_fail(SWIG_TypeError, "$type", $symname, $argnum);
    488     } else {
    489       swig::Iterator_T<$type > *iter_t = dynamic_cast<swig::Iterator_T<$type > *>(iter);
    490       if (iter_t) {
    491 	$1 = iter_t->get_current();
    492       } else {
    493 	%argument_fail(SWIG_TypeError, "$type", $symname, $argnum);
    494       }
    495     }
    496   }
    497 
    498   %typecheck(%checkcode(ITERATOR),noblock=1,fragment="RubySequence_Cont")
    499     const_iterator, const_reverse_iterator {
    500     swig::ConstIterator *iter = 0;
    501     int res = SWIG_ConvertPtr($input, %as_voidptrptr(&iter),
    502 			      swig::ConstIterator::descriptor(), 0);
    503     $1 = (SWIG_IsOK(res) && iter && (dynamic_cast<swig::ConstIterator_T<$type > *>(iter) != 0));
    504   }
    505 
    506   %typecheck(%checkcode(ITERATOR),noblock=1,fragment="RubySequence_Cont")
    507     iterator, reverse_iterator {
    508     swig::ConstIterator *iter = 0;
    509     int res = SWIG_ConvertPtr($input, %as_voidptrptr(&iter),
    510 			      swig::Iterator::descriptor(), 0);
    511     $1 = (SWIG_IsOK(res) && iter && (dynamic_cast<swig::Iterator_T<$type > *>(iter) != 0));
    512   }
    513 
    514   %fragment("RubySequence_Cont");
    515 
    516 //   %newobject iterator;
    517 //   %newobject const_iterator;
    518 //   %extend  {
    519 //     swig::Iterator* iterator(VALUE* RUBY_SELF) {
    520 //       return swig::make_nonconst_iterator($self->begin(), $self->begin(),
    521 // 				             $self->end(), *RUBY_SELF);
    522 //     }
    523 
    524 //     swig::ConstIterator* const_iterator(VALUE* RUBY_SELF) {
    525 //       return swig::make_const_iterator($self->begin(), $self->begin(),
    526 // 					$self->end(), *RUBY_SELF);
    527 //     }
    528 //   }
    529 #endif //SWIG_EXPORT_ITERATOR_METHODS
    530 %enddef
    531 
    532 
    533 /**** The Ruby container methods  ****/
    534 
    535 
    536 
    537 %define %swig_container_methods(Container...)
    538 
    539   %extend {
    540 
    541   %newobject dup;
    542   Container* dup()
    543     {
    544       return new Container(*$self);
    545     }
    546 
    547   }
    548 
    549 %enddef
    550 
    551 
    552 /**
    553  * Macro used to define common Ruby printing methods for STL container
    554  *
    555  */
    556 %define %swig_sequence_printing_methods(Sequence...)
    557 
    558   %extend {
    559 
    560   VALUE inspect()
    561     {
    562       Sequence::const_iterator i = $self->begin();
    563       Sequence::const_iterator e = $self->end();
    564       const char *type_name = swig::type_name< Sequence >();
    565       VALUE str = rb_str_new2(type_name);
    566       str = rb_str_cat2( str, " [" );
    567       bool comma = false;
    568       VALUE tmp;
    569       for ( ; i != e; ++i, comma = true )
    570 	{
    571 	  if (comma) str = rb_str_cat2( str, "," );
    572 	  tmp = swig::from< Sequence::value_type >( *i );
    573 	  tmp = rb_inspect( tmp );
    574 	  str = rb_str_buf_append( str, tmp );
    575 	}
    576       str = rb_str_cat2( str, "]" );
    577       return str;
    578     }
    579 
    580   VALUE to_a()
    581     {
    582       Sequence::const_iterator i = $self->begin();
    583       Sequence::const_iterator e = $self->end();
    584       VALUE ary = rb_ary_new2( std::distance( i, e ) );
    585       VALUE tmp;
    586       for ( ; i != e; ++i )
    587 	{
    588 	  tmp = swig::from< Sequence::value_type >( *i );
    589 	  rb_ary_push( ary, tmp );
    590 	}
    591       return ary;
    592     }
    593 
    594   VALUE to_s()
    595     {
    596       Sequence::iterator i = $self->begin();
    597       Sequence::iterator e = $self->end();
    598       VALUE str = rb_str_new2( "" );
    599       VALUE tmp;
    600       for ( ; i != e; ++i )
    601 	{
    602 	  tmp = swig::from< Sequence::value_type >( *i );
    603 	  tmp = rb_obj_as_string( tmp );
    604 	  str = rb_str_buf_append( str, tmp );
    605 	}
    606       return str;
    607     }
    608 }
    609 %enddef
    610 
    611 
    612 /**
    613  * Macro used to add common methods to all STL sequence-type containers
    614  *
    615  */
    616 %define %swig_sequence_methods_common(Sequence...)
    617   %swig_container_methods(%arg(Sequence))
    618   %swig_sequence_iterator(%arg(Sequence))
    619   %swig_sequence_printing_methods(%arg(Sequence))
    620 
    621   %fragment("RubySequence_Base");
    622 
    623   %extend {
    624 
    625 
    626   VALUE slice( difference_type i, difference_type j )
    627     {
    628 	if ( j <= 0 ) return Qnil;
    629 	std::size_t len = $self->size();
    630 	if ( i < 0 ) i = len - i;
    631 	j += i;
    632 	if ( static_cast<std::size_t>(j) >= len ) j = len-1;
    633 
    634 	VALUE r = Qnil;
    635 	try {
    636 	  r = swig::from< const Sequence* >( swig::getslice(self, i, j) );
    637 	}
    638 	catch( std::out_of_range )
    639 	  {
    640 	  }
    641 	return r;
    642       }
    643 
    644 
    645     Sequence* each()
    646       {
    647 	if ( !rb_block_given_p() )
    648 	  rb_raise( rb_eArgError, "no block given");
    649 
    650 	VALUE r;
    651 	Sequence::const_iterator i = self->begin();
    652 	Sequence::const_iterator e = self->end();
    653 	for ( ; i != e; ++i )
    654 	  {
    655 	    r = swig::from< Sequence::value_type >(*i);
    656 	    rb_yield(r);
    657 	  }
    658 
    659 	return self;
    660       }
    661 
    662     %newobject select;
    663     Sequence* select() {
    664       if ( !rb_block_given_p() )
    665 	rb_raise( rb_eArgError, "no block given" );
    666 
    667       Sequence* r = new Sequence;
    668       Sequence::const_iterator i = $self->begin();
    669       Sequence::const_iterator e = $self->end();
    670       for ( ; i != e; ++i )
    671 	{
    672 	  VALUE v = swig::from< Sequence::value_type >(*i);
    673 	  if ( RTEST( rb_yield(v) ) )
    674 	    $self->insert( r->end(), *i);
    675 	}
    676 
    677       return r;
    678     }
    679 
    680     VALUE delete_at(difference_type i) {
    681       VALUE r = Qnil;
    682       try {
    683 	Sequence::iterator at = swig::getpos(self, i);
    684 	r = swig::from< Sequence::value_type >( *(at) );
    685 	$self->erase(at);
    686       }
    687       catch (std::out_of_range)
    688 	{
    689 	}
    690       return r;
    691     }
    692 
    693 
    694     VALUE __delete2__(const value_type& i) {
    695       VALUE r = Qnil;
    696       return r;
    697     }
    698 
    699   }
    700 %enddef
    701 
    702 
    703 /**
    704  * Macro used to add functions for back insertion of values in
    705  * STL Sequence containers
    706  *
    707  */
    708 %define %swig_sequence_back_inserters( Sequence... )
    709   %extend {
    710 
    711     VALUE pop() {
    712       if ($self->empty()) return Qnil;
    713       Sequence::value_type x = self->back();
    714       $self->pop_back();
    715       return swig::from< Sequence::value_type >( x );
    716     }
    717 
    718     %alias push "<<";
    719     const value_type push( const value_type& e ) {
    720       $self->push_back( e );
    721       return e;
    722     }
    723 
    724     %newobject reject;
    725     Sequence* reject() {
    726       if ( !rb_block_given_p() )
    727 	rb_raise( rb_eArgError, "no block given" );
    728 
    729       Sequence* r = new Sequence;
    730       std::remove_copy_if( $self->begin(), $self->end(),
    731 			   std::back_inserter(*r),
    732 			   swig::yield< Sequence::value_type >() );
    733       return r;
    734     }
    735 
    736   }
    737 %enddef
    738 
    739 %define %swig_sequence_methods_extra(Sequence...)
    740   %extend {
    741     %alias reject_bang "delete_if";
    742     Sequence* reject_bang() {
    743       if ( !rb_block_given_p() )
    744 	rb_raise( rb_eArgError, "no block given" );
    745 
    746       $self->erase( std::remove_if( $self->begin(), $self->end(),
    747             swig::yield< Sequence::value_type >() ), $self->end() );
    748       return $self;
    749     }
    750   }
    751 %enddef
    752 
    753 /**
    754  * Macro used to add functions for Sequences
    755  *
    756  */
    757 %define %swig_sequence_methods(Sequence...)
    758   %swig_sequence_methods_common(%arg(Sequence));
    759   %swig_sequence_methods_extra(%arg(Sequence));
    760   %swig_sequence_back_inserters(%arg(Sequence));
    761 
    762   %extend {
    763 
    764     VALUE at(difference_type i) const {
    765       VALUE r = Qnil;
    766       try {
    767 	r = swig::from< Sequence::value_type >( *(swig::cgetpos(self, i)) );
    768       }
    769       catch( std::out_of_range )
    770 	{
    771 	}
    772       return r;
    773     }
    774 
    775     VALUE __getitem__(difference_type i, difference_type j) const {
    776       if ( j <= 0 ) return Qnil;
    777       std::size_t len = $self->size();
    778       if ( i < 0 ) i = len - i;
    779       j += i; if ( static_cast<std::size_t>(j) >= len ) j = len-1;
    780 
    781       VALUE r = Qnil;
    782       try {
    783 	r = swig::from< const Sequence* >( swig::getslice(self, i, j) );
    784       }
    785       catch( std::out_of_range )
    786 	{
    787 	}
    788       return r;
    789     }
    790 
    791     VALUE __getitem__(difference_type i) const {
    792       VALUE r = Qnil;
    793       try {
    794 	r = swig::from< Sequence::value_type >( *(swig::cgetpos(self, i)) );
    795       }
    796       catch( std::out_of_range )
    797 	{
    798 	}
    799       return r;
    800     }
    801 
    802     VALUE __getitem__(VALUE i) const {
    803       if ( rb_obj_is_kind_of( i, rb_cRange ) == Qfalse )
    804 	{
    805 	  rb_raise( rb_eTypeError, "not a valid index or range" );
    806 	}
    807 
    808       VALUE r = Qnil;
    809       static ID id_end   = rb_intern("end");
    810       static ID id_start = rb_intern("begin");
    811       static ID id_noend = rb_intern("exclude_end?");
    812 
    813       VALUE start = rb_funcall( i, id_start, 0 );
    814       VALUE end   = rb_funcall( i, id_end, 0 );
    815       bool  noend = ( rb_funcall( i, id_noend, 0 ) == Qtrue );
    816 
    817       int len = $self->size();
    818 
    819       int s = NUM2INT( start );
    820       if ( s < 0 ) s = len + s;
    821       else if ( s >= len ) return Qnil;
    822 
    823       int e = NUM2INT( end );
    824       if ( e < 0 ) e = len + e;
    825 
    826       if ( e < s ) return Qnil; //std::swap( s, e );
    827 
    828       if ( noend ) e -= 1;
    829       if ( e >= len ) e = len - 1;
    830 
    831       return swig::from< Sequence* >( swig::getslice(self, s, e+1) );
    832     }
    833 
    834     VALUE __setitem__(difference_type i, const value_type& x)
    835       {
    836 	std::size_t len = $self->size();
    837 	if ( i < 0 ) i = len - i;
    838 	else if ( static_cast<std::size_t>(i) >= len )
    839 	  $self->resize( i+1, x );
    840 	else
    841 	  *(swig::getpos(self,i)) = x;
    842 
    843 	return swig::from< Sequence::value_type >( x );
    844       }
    845 
    846     VALUE __setitem__(difference_type i, difference_type j, const Sequence& v)
    847       throw (std::invalid_argument) {
    848 
    849       if ( j <= 0 ) return Qnil;
    850       std::size_t len = $self->size();
    851       if ( i < 0 ) i = len - i;
    852       j += i;
    853       if ( static_cast<std::size_t>(j) >= len ) {
    854 	$self->resize( j+1, *(v.begin()) );
    855 	j = len-1;
    856       }
    857 
    858       VALUE r = Qnil;
    859       swig::setslice(self, i, j, v);
    860       r = swig::from< const Sequence* >( &v );
    861       return r;
    862     }
    863 
    864  }
    865 %enddef
    866 
    867 %define %swig_sequence_methods_val(Sequence...)
    868   %swig_sequence_methods(%arg(Sequence))
    869 %enddef
    870 
    871 
    872 /**
    873  * Macro used to add functions for front insertion of
    874  * elements in STL sequence containers that support it.
    875  *
    876  */
    877 %define %swig_sequence_front_inserters( Sequence... )
    878 
    879 %extend {
    880 
    881   VALUE shift()
    882     {
    883       if ($self->empty()) return Qnil;
    884       Sequence::value_type x = self->front();
    885       $self->erase( $self->begin() );
    886       return swig::from< Sequence::value_type >( x );
    887     }
    888 
    889   %typemap(in) (int argc, VALUE* argv) {
    890     $1 = argc - 1;
    891     $2 = argv + 1;
    892   }
    893 
    894   Sequence* insert( difference_type pos, int argc, VALUE* argv, ... )
    895     {
    896       std::size_t len = $self->size();
    897       std::size_t   i = swig::check_index( pos, len, true );
    898       Sequence::iterator start;
    899 
    900       VALUE elem = argv[0];
    901       int idx = 0;
    902       try {
    903 	Sequence::value_type val = swig::as<Sequence::value_type>( elem, true );
    904 	if ( i >= len ) {
    905 	  $self->resize(i-1, val);
    906 	  return $self;
    907 	}
    908 	start = $self->begin();
    909 	std::advance( start, i );
    910 	$self->insert( start++, val );
    911 
    912 	for ( ++idx; idx < argc; ++idx )
    913 	  {
    914 	    elem = argv[idx];
    915 	    val = swig::as<Sequence::value_type>( elem );
    916 	    $self->insert( start++, val );
    917 	  }
    918 
    919       }
    920       catch( std::invalid_argument )
    921 	{
    922 	  rb_raise( rb_eArgError, "%s",
    923 		    Ruby_Format_TypeError( "",
    924 					   swig::type_name<Sequence::value_type>(),
    925 					   __FUNCTION__, idx+2, elem ));
    926 	}
    927 
    928 
    929       return $self;
    930     }
    931 
    932   %typemap(in) (int argc, VALUE* argv) {
    933     $1 = argc;
    934     $2 = argv;
    935   }
    936 
    937   Sequence* unshift( int argc, VALUE* argv, ... )
    938     {
    939       for ( int idx = argc-1; idx >= 0; --idx )
    940 	{
    941 	  Sequence::iterator start = $self->begin();
    942 	  VALUE elem = argv[idx];
    943 	  try {
    944 	    Sequence::value_type val = swig::as<Sequence::value_type>( elem, true );
    945 	    $self->insert( start, val );
    946 	  }
    947 	  catch( std::invalid_argument )
    948 	    {
    949 	      rb_raise( rb_eArgError, "%s",
    950 			Ruby_Format_TypeError( "",
    951 					       swig::type_name<Sequence::value_type>(),
    952 					       __FUNCTION__, idx+2, elem ));
    953 	    }
    954 	}
    955 
    956       return $self;
    957     }
    958 
    959 }
    960 %enddef
    961 
    962 
    963 //
    964 // Common fragments
    965 //
    966 
    967 %fragment("StdSequenceTraits","header",
    968 	  fragment="StdTraits",
    969 	  fragment="RubySequence_Cont",
    970 	  fragment="GC_VALUE_definition")
    971 {
    972 namespace swig {
    973   template <class RubySeq, class Seq>
    974   inline void
    975   assign(const RubySeq& rubyseq, Seq* seq) {
    976     // seq->assign(rubyseq.begin(), rubyseq.end()); // not used as not always implemented
    977     typedef typename RubySeq::value_type value_type;
    978     typename RubySeq::const_iterator it = rubyseq.begin();
    979     for (;it != rubyseq.end(); ++it) {
    980       seq->insert(seq->end(),(value_type)(*it));
    981     }
    982   }
    983 
    984   template <class Seq, class T = typename Seq::value_type >
    985   struct traits_asptr_stdseq {
    986     typedef Seq sequence;
    987     typedef T value_type;
    988 
    989     static int asptr(VALUE obj, sequence **seq) {
    990       if (rb_obj_is_kind_of(obj, rb_cArray) == Qtrue) {
    991 	try {
    992 	  RubySequence_Cont<value_type> rubyseq(obj);
    993 	  if (seq) {
    994 	    sequence *pseq = new sequence();
    995 	    assign(rubyseq, pseq);
    996 	    *seq = pseq;
    997 	    return SWIG_NEWOBJ;
    998 	  } else {
    999 	    return rubyseq.check() ? SWIG_OK : SWIG_ERROR;
   1000 	  }
   1001 	} catch (std::exception& e) {
   1002 	  if (seq) {
   1003 	    VALUE lastErr = rb_gv_get("$!");
   1004 	    if (lastErr == Qnil) {
   1005 	      rb_raise(rb_eTypeError, "%s", e.what());
   1006 	    }
   1007 	  }
   1008 	  return SWIG_ERROR;
   1009 	}
   1010       } else {
   1011 	sequence *p;
   1012 	if (SWIG_ConvertPtr(obj,(void**)&p,
   1013 			    swig::type_info<sequence>(),0) == SWIG_OK) {
   1014 	  if (seq) *seq = p;
   1015 	  return SWIG_OLDOBJ;
   1016 	}
   1017       }
   1018       return SWIG_ERROR;
   1019     }
   1020   };
   1021 
   1022   // Partial specialization for GC_VALUE's.  No need to typecheck each
   1023   // element.
   1024   template< class Seq >
   1025   struct traits_asptr_stdseq< Seq, swig::GC_VALUE > {
   1026     typedef Seq sequence;
   1027     typedef swig::GC_VALUE value_type;
   1028 
   1029     static int asptr(VALUE obj, sequence **seq) {
   1030       if (rb_obj_is_kind_of(obj, rb_cArray) == Qtrue) {
   1031 	try {
   1032 	  if (seq) {
   1033 	    RubySequence_Cont<value_type> rubyseq(obj);
   1034 	    sequence *pseq = new sequence();
   1035 	    assign(rubyseq, pseq);
   1036 	    *seq = pseq;
   1037 	    return SWIG_NEWOBJ;
   1038 	  } else {
   1039 	    return true;
   1040 	  }
   1041 	} catch (std::exception& e) {
   1042 	  if (seq) {
   1043 	    VALUE lastErr = rb_gv_get("$!");
   1044 	    if (lastErr == Qnil) {
   1045 	      rb_raise(rb_eTypeError, "%s", e.what());
   1046 	    }
   1047 	  }
   1048 	  return SWIG_ERROR;
   1049 	}
   1050       } else {
   1051 	sequence *p;
   1052 	if (SWIG_ConvertPtr(obj,(void**)&p,
   1053 			    swig::type_info<sequence>(),0) == SWIG_OK) {
   1054 	  if (seq) *seq = p;
   1055 	  return SWIG_OLDOBJ;
   1056 	}
   1057       }
   1058       return SWIG_ERROR;
   1059     }
   1060   };
   1061 
   1062   template <class Seq, class T = typename Seq::value_type >
   1063   struct traits_from_stdseq {
   1064     typedef Seq sequence;
   1065     typedef T value_type;
   1066     typedef typename Seq::size_type size_type;
   1067     typedef typename sequence::const_iterator const_iterator;
   1068 
   1069     static VALUE from(const sequence& seq) {
   1070 #ifdef SWIG_RUBY_EXTRA_NATIVE_CONTAINERS
   1071       swig_type_info *desc = swig::type_info<sequence>();
   1072       if (desc && desc->clientdata) {
   1073 	return SWIG_NewPointerObj(new sequence(seq), desc, SWIG_POINTER_OWN);
   1074       }
   1075 #endif
   1076       size_type size = seq.size();
   1077       if (size <= (size_type)INT_MAX) {
   1078 	VALUE obj = rb_ary_new2((int)size);
   1079 	int i = 0;
   1080 	for (const_iterator it = seq.begin();
   1081 	     it != seq.end(); ++it, ++i) {
   1082 	  rb_ary_push(obj, swig::from< value_type >(*it));
   1083 	}
   1084 	rb_obj_freeze(obj);  // treat as immutable result
   1085 	return obj;
   1086       } else {
   1087 	rb_raise(rb_eRangeError,"sequence size not valid in ruby");
   1088 	return Qnil;
   1089       }
   1090     }
   1091   };
   1092 }
   1093 }
   1094 
   1095 
   1096 %include <rubycontainer_extended.swg>
   1097