1 /* ----------------------------------------------------------------------------- 2 * octcontainer.swg 3 * 4 * Octave cell <-> C++ container wrapper 5 * 6 * This wrapper, and its iterator, allows a general use (and reuse) of 7 * the mapping between C++ and Octave, 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 <octiterators.swg> 26 27 // The Octave C++ Wrap 28 29 %insert(header) %{ 30 #include <stdexcept> 31 %} 32 33 %include <std_except.i> 34 35 %fragment(SWIG_Traits_frag(octave_value),"header",fragment="StdTraits") { 36 namespace swig { 37 template <> struct traits<octave_value > { 38 typedef value_category category; 39 static const char* type_name() { return "octave_value"; } 40 }; 41 42 template <> struct traits_from<octave_value> { 43 typedef octave_value value_type; 44 static octave_value from(const value_type& val) { 45 return val; 46 } 47 }; 48 49 template <> 50 struct traits_check<octave_value, value_category> { 51 static bool check(const octave_value&) { 52 return true; 53 } 54 }; 55 56 template <> struct traits_asval<octave_value > { 57 typedef octave_value value_type; 58 static int asval(const octave_value& obj, value_type *val) { 59 if (val) *val = obj; 60 return SWIG_OK; 61 } 62 }; 63 } 64 } 65 66 %fragment("OctSequence_Base","header",fragment="<stddef.h>") 67 { 68 %#include <functional> 69 70 namespace std { 71 template <> 72 struct less <octave_value>: public binary_function<octave_value, octave_value, bool> 73 { 74 bool 75 operator()(const octave_value& v, const octave_value& w) const 76 { 77 octave_value res = do_binary_op(octave_value::op_le,v,w); 78 return res.is_true(); 79 } 80 }; 81 } 82 83 namespace swig { 84 inline size_t 85 check_index(ptrdiff_t i, size_t size, bool insert = false) { 86 if ( i < 0 ) { 87 if ((size_t) (-i) <= size) 88 return (size_t) (i + size); 89 } else if ( (size_t) i < size ) { 90 return (size_t) i; 91 } else if (insert && ((size_t) i == size)) { 92 return size; 93 } 94 95 throw std::out_of_range("index out of range"); 96 } 97 98 inline size_t 99 slice_index(ptrdiff_t i, size_t size) { 100 if ( i < 0 ) { 101 if ((size_t) (-i) <= size) { 102 return (size_t) (i + size); 103 } else { 104 throw std::out_of_range("index out of range"); 105 } 106 } else { 107 return ( (size_t) i < size ) ? ((size_t) i) : size; 108 } 109 } 110 111 template <class Sequence, class Difference> 112 inline typename Sequence::iterator 113 getpos(Sequence* self, Difference i) { 114 typename Sequence::iterator pos = self->begin(); 115 std::advance(pos, check_index(i,self->size())); 116 return pos; 117 } 118 119 template <class Sequence, class Difference> 120 inline typename Sequence::const_iterator 121 cgetpos(const Sequence* self, Difference i) { 122 typename Sequence::const_iterator pos = self->begin(); 123 std::advance(pos, check_index(i,self->size())); 124 return pos; 125 } 126 127 template <class Sequence, class Difference> 128 inline Sequence* 129 getslice(const Sequence* self, Difference i, Difference j) { 130 typename Sequence::size_type size = self->size(); 131 typename Sequence::size_type ii = swig::check_index(i, size); 132 typename Sequence::size_type jj = swig::slice_index(j, size); 133 134 if (jj > ii) { 135 typename Sequence::const_iterator vb = self->begin(); 136 typename Sequence::const_iterator ve = self->begin(); 137 std::advance(vb,ii); 138 std::advance(ve,jj); 139 return new Sequence(vb, ve); 140 } else { 141 return new Sequence(); 142 } 143 } 144 145 template <class Sequence, class Difference, class InputSeq> 146 inline void 147 setslice(Sequence* self, Difference i, Difference j, const InputSeq& v) { 148 typename Sequence::size_type size = self->size(); 149 typename Sequence::size_type ii = swig::check_index(i, size, true); 150 typename Sequence::size_type jj = swig::slice_index(j, size); 151 if (jj < ii) jj = ii; 152 size_t ssize = jj - ii; 153 if (ssize <= v.size()) { 154 typename Sequence::iterator sb = self->begin(); 155 typename InputSeq::const_iterator vmid = v.begin(); 156 std::advance(sb,ii); 157 std::advance(vmid, jj - ii); 158 self->insert(std::copy(v.begin(), vmid, sb), vmid, v.end()); 159 } else { 160 typename Sequence::iterator sb = self->begin(); 161 typename Sequence::iterator se = self->begin(); 162 std::advance(sb,ii); 163 std::advance(se,jj); 164 self->erase(sb,se); 165 self->insert(sb, v.begin(), v.end()); 166 } 167 } 168 169 template <class Sequence, class Difference> 170 inline void 171 delslice(Sequence* self, Difference i, Difference j) { 172 typename Sequence::size_type size = self->size(); 173 typename Sequence::size_type ii = swig::check_index(i, size, true); 174 typename Sequence::size_type jj = swig::slice_index(j, size); 175 if (jj > ii) { 176 typename Sequence::iterator sb = self->begin(); 177 typename Sequence::iterator se = self->begin(); 178 std::advance(sb,ii); 179 std::advance(se,jj); 180 self->erase(sb,se); 181 } 182 } 183 } 184 } 185 186 %fragment("OctSequence_Cont","header", 187 fragment="StdTraits", 188 fragment="OctSequence_Base", 189 fragment="OctSwigIterator_T") 190 { 191 namespace swig 192 { 193 template <class T> 194 struct OctSequence_Ref // * octave can't support these, because of how assignment works 195 { 196 OctSequence_Ref(const octave_value& seq, int index) 197 : _seq(seq), _index(index) 198 { 199 } 200 201 operator T () const 202 { 203 // swig::SwigVar_PyObject item = OctSequence_GetItem(_seq, _index); 204 octave_value item; // * todo 205 try { 206 return swig::as<T>(item, true); 207 } catch (std::exception& e) { 208 char msg[1024]; 209 sprintf(msg, "in sequence element %d ", _index); 210 if (!Octave_Error_Occurred()) { 211 %type_error(swig::type_name<T>()); 212 } 213 SWIG_Octave_AddErrorMsg(msg); 214 SWIG_Octave_AddErrorMsg(e.what()); 215 throw; 216 } 217 } 218 219 OctSequence_Ref& operator=(const T& v) 220 { 221 // OctSequence_SetItem(_seq, _index, swig::from<T>(v)); 222 // * todo 223 return *this; 224 } 225 226 private: 227 octave_value _seq; 228 int _index; 229 }; 230 231 template <class T> 232 struct OctSequence_ArrowProxy 233 { 234 OctSequence_ArrowProxy(const T& x): m_value(x) {} 235 const T* operator->() const { return &m_value; } 236 operator const T*() const { return &m_value; } 237 T m_value; 238 }; 239 240 template <class T, class Reference > 241 struct OctSequence_InputIterator 242 { 243 typedef OctSequence_InputIterator<T, Reference > self; 244 245 typedef std::random_access_iterator_tag iterator_category; 246 typedef Reference reference; 247 typedef T value_type; 248 typedef T* pointer; 249 typedef int difference_type; 250 251 OctSequence_InputIterator() 252 { 253 } 254 255 OctSequence_InputIterator(const octave_value& seq, int index) 256 : _seq(seq), _index(index) 257 { 258 } 259 260 reference operator*() const 261 { 262 return reference(_seq, _index); 263 } 264 265 OctSequence_ArrowProxy<T> 266 operator->() const { 267 return OctSequence_ArrowProxy<T>(operator*()); 268 } 269 270 bool operator==(const self& ri) const 271 { 272 return (_index == ri._index); 273 } 274 275 bool operator!=(const self& ri) const 276 { 277 return !(operator==(ri)); 278 } 279 280 self& operator ++ () 281 { 282 ++_index; 283 return *this; 284 } 285 286 self& operator -- () 287 { 288 --_index; 289 return *this; 290 } 291 292 self& operator += (difference_type n) 293 { 294 _index += n; 295 return *this; 296 } 297 298 self operator +(difference_type n) const 299 { 300 return self(_seq, _index + n); 301 } 302 303 self& operator -= (difference_type n) 304 { 305 _index -= n; 306 return *this; 307 } 308 309 self operator -(difference_type n) const 310 { 311 return self(_seq, _index - n); 312 } 313 314 difference_type operator - (const self& ri) const 315 { 316 return _index - ri._index; 317 } 318 319 bool operator < (const self& ri) const 320 { 321 return _index < ri._index; 322 } 323 324 reference 325 operator[](difference_type n) const 326 { 327 return reference(_seq, _index + n); 328 } 329 330 private: 331 octave_value _seq; 332 difference_type _index; 333 }; 334 335 template <class T> 336 struct OctSequence_Cont 337 { 338 typedef OctSequence_Ref<T> reference; 339 typedef const OctSequence_Ref<T> const_reference; 340 typedef T value_type; 341 typedef T* pointer; 342 typedef int difference_type; 343 typedef int size_type; 344 typedef const pointer const_pointer; 345 typedef OctSequence_InputIterator<T, reference> iterator; 346 typedef OctSequence_InputIterator<T, const_reference> const_iterator; 347 348 OctSequence_Cont(const octave_value& seq) : _seq(seq) 349 { 350 // * assert that we have map type etc. 351 /* 352 if (!OctSequence_Check(seq)) { 353 throw std::invalid_argument("a sequence is expected"); 354 } 355 _seq = seq; 356 Py_INCREF(_seq); 357 */ 358 } 359 360 ~OctSequence_Cont() 361 { 362 } 363 364 size_type size() const 365 { 366 // return static_cast<size_type>(OctSequence_Size(_seq)); 367 return 0; // * todo 368 } 369 370 bool empty() const 371 { 372 return size() == 0; 373 } 374 375 iterator begin() 376 { 377 return iterator(_seq, 0); 378 } 379 380 const_iterator begin() const 381 { 382 return const_iterator(_seq, 0); 383 } 384 385 iterator end() 386 { 387 return iterator(_seq, size()); 388 } 389 390 const_iterator end() const 391 { 392 return const_iterator(_seq, size()); 393 } 394 395 reference operator[](difference_type n) 396 { 397 return reference(_seq, n); 398 } 399 400 const_reference operator[](difference_type n) const 401 { 402 return const_reference(_seq, n); 403 } 404 405 bool check(bool set_err = true) const 406 { 407 int s = size(); 408 for (int i = 0; i < s; ++i) { 409 // swig::SwigVar_PyObject item = OctSequence_GetItem(_seq, i); 410 octave_value item; // * todo 411 if (!swig::check<value_type>(item)) { 412 if (set_err) { 413 char msg[1024]; 414 sprintf(msg, "in sequence element %d", i); 415 SWIG_Error(SWIG_RuntimeError, msg); 416 } 417 return false; 418 } 419 } 420 return true; 421 } 422 423 private: 424 octave_value _seq; 425 }; 426 427 } 428 } 429 430 %define %swig_sequence_iterator(Sequence...) 431 #if defined(SWIG_EXPORT_ITERATOR_METHODS) 432 class iterator; 433 class reverse_iterator; 434 class const_iterator; 435 class const_reverse_iterator; 436 437 %typemap(out,noblock=1,fragment="OctSequence_Cont") 438 iterator, reverse_iterator, const_iterator, const_reverse_iterator { 439 $result = SWIG_NewPointerObj(swig::make_output_iterator(%static_cast($1,const $type &)), 440 swig::OctSwigIterator::descriptor(),SWIG_POINTER_OWN); 441 } 442 %typemap(out,fragment="OctSequence_Cont") 443 std::pair<iterator, iterator>, std::pair<const_iterator, const_iterator> { 444 octave_value_list tmpc; 445 tmpc.append(SWIG_NewPointerObj(swig::make_output_iterator(%static_cast($1,const $type &).first), 446 swig::OctSwigIterator::descriptor(),SWIG_POINTER_OWN)); 447 tmpc.append(SWIG_NewPointerObj(swig::make_output_iterator(%static_cast($1,const $type &).second), 448 swig::OctSwigIterator::descriptor(),SWIG_POINTER_OWN)); 449 $result = Cell(tmpc); 450 } 451 452 %fragment("SwigPyPairBoolOutputIterator","header",fragment=SWIG_From_frag(bool),fragment="OctSequence_Cont") {} 453 454 %typemap(out,fragment="OctPairBoolOutputIterator") 455 std::pair<iterator, bool>, std::pair<const_iterator, bool> { 456 octave_value_list tmpc; 457 tmpc.append(SWIG_NewPointerObj(swig::make_output_iterator(%static_cast($1,const $type &).first), 458 swig::OctSwigIterator::descriptor(),SWIG_POINTER_OWN)); 459 tmpc.append(SWIG_From(bool)(%static_cast($1,const $type &).second)); 460 $result = Cell(tmpc); 461 } 462 463 %typemap(in,noblock=1,fragment="OctSequence_Cont") 464 iterator(swig::OctSwigIterator *iter = 0, int res), 465 reverse_iterator(swig::OctSwigIterator *iter = 0, int res), 466 const_iterator(swig::OctSwigIterator *iter = 0, int res), 467 const_reverse_iterator(swig::OctSwigIterator *iter = 0, int res) { 468 res = SWIG_ConvertPtr($input, %as_voidptrptr(&iter), swig::OctSwigIterator::descriptor(), 0); 469 if (!SWIG_IsOK(res) || !iter) { 470 %argument_fail(SWIG_TypeError, "$type", $symname, $argnum); 471 } else { 472 swig::OctSwigIterator_T<$type > *iter_t = dynamic_cast<swig::OctSwigIterator_T<$type > *>(iter); 473 if (iter_t) { 474 $1 = iter_t->get_current(); 475 } else { 476 %argument_fail(SWIG_TypeError, "$type", $symname, $argnum); 477 } 478 } 479 } 480 481 %typecheck(%checkcode(ITERATOR),noblock=1,fragment="OctSequence_Cont") 482 iterator, reverse_iterator, const_iterator, const_reverse_iterator { 483 swig::OctSwigIterator *iter = 0; 484 int res = SWIG_ConvertPtr($input, %as_voidptrptr(&iter), swig::OctSwigIterator::descriptor(), 0); 485 $1 = (SWIG_IsOK(res) && iter && (dynamic_cast<swig::OctSwigIterator_T<$type > *>(iter) != 0)); 486 } 487 488 %fragment("OctSequence_Cont"); 489 #endif //SWIG_EXPORT_ITERATOR_METHODS 490 %enddef 491 492 // The octave container methods 493 494 %define %swig_container_methods(Container...) 495 %enddef 496 497 %define %swig_sequence_methods_common(Sequence...) 498 %swig_sequence_iterator(%arg(Sequence)) 499 %swig_container_methods(%arg(Sequence)) 500 501 %fragment("OctSequence_Base"); 502 503 %extend { 504 value_type pop() throw (std::out_of_range) { 505 if (self->size() == 0) 506 throw std::out_of_range("pop from empty container"); 507 Sequence::value_type x = self->back(); 508 self->pop_back(); 509 return x; 510 } 511 512 value_type __paren__(difference_type i) throw (std::out_of_range) { 513 return *(swig::cgetpos(self, i)); 514 } 515 516 void __paren_asgn__(difference_type i, value_type x) throw (std::out_of_range) { 517 *(swig::getpos(self,i)) = x; 518 } 519 520 void append(value_type x) { 521 self->push_back(x); 522 } 523 } 524 525 %enddef 526 527 %define %swig_sequence_methods(Sequence...) 528 %swig_sequence_methods_common(%arg(Sequence)) 529 %enddef 530 531 %define %swig_sequence_methods_val(Sequence...) 532 %swig_sequence_methods_common(%arg(Sequence)) 533 %enddef 534 535 // 536 // Common fragments 537 // 538 539 %fragment("StdSequenceTraits","header", 540 fragment="StdTraits", 541 fragment="OctSequence_Cont") 542 { 543 namespace swig { 544 template <class OctSeq, class Seq> 545 inline void 546 assign(const OctSeq& octseq, Seq* seq) { 547 %#ifdef SWIG_STD_NOASSIGN_STL 548 typedef typename OctSeq::value_type value_type; 549 typename OctSeq::const_iterator it = octseq.begin(); 550 for (;it != octseq.end(); ++it) { 551 seq->insert(seq->end(),(value_type)(*it)); 552 } 553 %#else 554 seq->assign(octseq.begin(), octseq.end()); 555 %#endif 556 } 557 558 template <class Seq, class T = typename Seq::value_type > 559 struct traits_asptr_stdseq { 560 typedef Seq sequence; 561 typedef T value_type; 562 563 static int asptr(const octave_value& obj, sequence **seq) { 564 if (!obj.is_defined() || Swig::swig_value_deref(obj)) { 565 sequence *p; 566 if (SWIG_ConvertPtr(obj,(void**)&p, 567 swig::type_info<sequence>(),0) == SWIG_OK) { 568 if (seq) *seq = p; 569 return SWIG_OLDOBJ; 570 } 571 } else if (obj.is_cell()) { 572 try { 573 OctSequence_Cont<value_type> octseq(obj); 574 if (seq) { 575 sequence *pseq = new sequence(); 576 assign(octseq, pseq); 577 *seq = pseq; 578 return SWIG_NEWOBJ; 579 } else { 580 return octseq.check() ? SWIG_OK : SWIG_ERROR; 581 } 582 } catch (std::exception& e) { 583 if (seq&&!error_state) 584 error("swig type error: %s",e.what()); 585 return SWIG_ERROR; 586 } 587 } 588 return SWIG_ERROR; 589 } 590 }; 591 592 template <class Seq, class T = typename Seq::value_type > 593 struct traits_from_stdseq { 594 typedef Seq sequence; 595 typedef T value_type; 596 typedef typename Seq::size_type size_type; 597 typedef typename sequence::const_iterator const_iterator; 598 599 static octave_value from(const sequence& seq) { 600 #ifdef SWIG_OCTAVE_EXTRA_NATIVE_CONTAINERS 601 swig_type_info *desc = swig::type_info<sequence>(); 602 if (desc && desc->clientdata) { 603 return SWIG_NewPointerObj(new sequence(seq), desc, SWIG_POINTER_OWN); 604 } 605 #endif 606 size_type size = seq.size(); 607 if (size <= (size_type)INT_MAX) { 608 Cell c(size,1); 609 int i = 0; 610 for (const_iterator it = seq.begin(); 611 it != seq.end(); ++it, ++i) { 612 c(i) = swig::from<value_type>(*it); 613 } 614 return c; 615 } else { 616 error("swig overflow error: sequence size not valid in octave"); 617 return octave_value(); 618 } 619 return octave_value(); 620 } 621 }; 622 } 623 } 624 625