Home | History | Annotate | Download | only in octave
      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