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