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