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