/* ----------------------------------------------------------------------------- * rubyiterators.swg * * Implement a C++ 'output' iterator for Ruby. * * Users can derive form the Iterator to implemet their * own iterators. As an example (real one since we use it for STL/STD * containers), the template Iterator_T does the * implementation for generic C++ iterators. * ----------------------------------------------------------------------------- */ %include <std_common.i> %fragment("ConstIterator","header",fragment="<stddef.h>",fragment="GC_VALUE_definition") { namespace swig { struct stop_iteration { }; /** * Abstract base class used to represent all iterators of STL containers. */ struct ConstIterator { public: typedef ConstIterator self_type; protected: GC_VALUE _seq; protected: ConstIterator(VALUE seq) : _seq(seq) { } // Random access iterator methods, but not required in Ruby virtual ptrdiff_t distance(const ConstIterator &x) const { throw std::invalid_argument("distance not supported"); } virtual bool equal (const ConstIterator &x) const { throw std::invalid_argument("equal not supported"); } virtual self_type* advance(ptrdiff_t n) { throw std::invalid_argument("advance not supported"); } public: virtual ~ConstIterator() {} // Access iterator method, required by Ruby virtual VALUE value() const { throw std::invalid_argument("value not supported"); return Qnil; }; virtual VALUE setValue( const VALUE& v ) { throw std::invalid_argument("value= not supported"); return Qnil; } virtual self_type* next( size_t n = 1 ) { return this->advance( n ); } virtual self_type* previous( size_t n = 1 ) { ptrdiff_t nn = n; return this->advance( -nn ); } virtual VALUE to_s() const { throw std::invalid_argument("to_s not supported"); return Qnil; } virtual VALUE inspect() const { throw std::invalid_argument("inspect not supported"); return Qnil; } virtual ConstIterator *dup() const { throw std::invalid_argument("dup not supported"); return NULL; } // // C++ common/needed methods. We emulate a bidirectional // operator, to be compatible with all the STL. // The iterator traits will then tell the STL what type of // iterator we really are. // ConstIterator() : _seq( Qnil ) { } ConstIterator( const self_type& b ) : _seq( b._seq ) { } self_type& operator=( const self_type& b ) { _seq = b._seq; return *this; } bool operator == (const ConstIterator& x) const { return equal(x); } bool operator != (const ConstIterator& x) const { return ! operator==(x); } // Pre-decrement operator self_type& operator--() { return *previous(); } // Pre-increment operator self_type& operator++() { return *next(); } // Post-decrement operator self_type operator--(int) { self_type r = *this; previous(); return r; } // Post-increment operator self_type operator++(int) { self_type r = *this; next(); return r; } ConstIterator& operator += (ptrdiff_t n) { return *advance(n); } ConstIterator& operator -= (ptrdiff_t n) { return *advance(-n); } ConstIterator* operator + (ptrdiff_t n) const { return dup()->advance(n); } ConstIterator* operator - (ptrdiff_t n) const { return dup()->advance(-n); } ptrdiff_t operator - (const ConstIterator& x) const { return x.distance(*this); } static swig_type_info* descriptor() { static int init = 0; static swig_type_info* desc = 0; if (!init) { desc = SWIG_TypeQuery("swig::ConstIterator *"); init = 1; } return desc; } }; /** * Abstract base class used to represent all non-const iterators of STL containers. * */ struct Iterator : public ConstIterator { public: typedef Iterator self_type; protected: Iterator(VALUE seq) : ConstIterator(seq) { } virtual self_type* advance(ptrdiff_t n) { throw std::invalid_argument("operation not supported"); } public: static swig_type_info* descriptor() { static int init = 0; static swig_type_info* desc = 0; if (!init) { desc = SWIG_TypeQuery("swig::Iterator *"); init = 1; } return desc; } virtual Iterator *dup() const { throw std::invalid_argument("dup not supported"); return NULL; } virtual self_type* next( size_t n = 1 ) { return this->advance( n ); } virtual self_type* previous( size_t n = 1 ) { ptrdiff_t nn = n; return this->advance( -nn ); } bool operator == (const ConstIterator& x) const { return equal(x); } bool operator != (const Iterator& x) const { return ! operator==(x); } Iterator& operator += (ptrdiff_t n) { return *advance(n); } Iterator& operator -= (ptrdiff_t n) { return *advance(-n); } Iterator* operator + (ptrdiff_t n) const { return dup()->advance(n); } Iterator* operator - (ptrdiff_t n) const { return dup()->advance(-n); } ptrdiff_t operator - (const Iterator& x) const { return x.distance(*this); } }; } } %fragment("ConstIterator_T","header",fragment="<stddef.h>",fragment="ConstIterator",fragment="StdTraits",fragment="StdIteratorTraits") { namespace swig { /** * Templated base classes for all custom const_iterators. * */ template<typename OutConstIterator> class ConstIterator_T : public ConstIterator { public: typedef OutConstIterator const_iter; typedef typename std::iterator_traits<const_iter>::value_type value_type; typedef ConstIterator_T<const_iter> self_type; protected: virtual bool equal (const ConstIterator &iter) const { const self_type *iters = dynamic_cast<const self_type *>(&iter); if (iters) { return (current == iters->get_current()); } else { throw std::invalid_argument("bad iterator type"); } } virtual ptrdiff_t distance(const ConstIterator &iter) const { const self_type *iters = dynamic_cast<const self_type *>(&iter); if (iters) { return std::distance(current, iters->get_current()); } else { throw std::invalid_argument("bad iterator type"); } } virtual ConstIterator* advance(ptrdiff_t n) { std::advance( current, n ); return this; } public: ConstIterator_T() : ConstIterator(Qnil) { } ConstIterator_T(const_iter curr, VALUE seq = Qnil) : ConstIterator(seq), current(curr) { } const const_iter& get_current() const { return current; } const value_type& operator*() const { return *current; } virtual VALUE inspect() const { VALUE ret = rb_str_new2("#<"); ret = rb_str_cat2( ret, rb_obj_classname(_seq) ); ret = rb_str_cat2( ret, "::const_iterator " ); VALUE cur = value(); ret = rb_str_concat( ret, rb_inspect(cur) ); ret = rb_str_cat2( ret, ">" ); return ret; } virtual VALUE to_s() const { VALUE ret = rb_str_new2( rb_obj_classname(_seq) ); ret = rb_str_cat2( ret, "::const_iterator " ); VALUE cur = value(); ret = rb_str_concat( ret, rb_obj_as_string(cur) ); return ret; } protected: const_iter current; }; /** * Templated base classes for all custom non-const iterators. * */ template<typename InOutIterator> class Iterator_T : public Iterator { public: typedef InOutIterator nonconst_iter; // Make this class iterator STL compatible, by using iterator_traits typedef typename std::iterator_traits<nonconst_iter >::iterator_category iterator_category; typedef typename std::iterator_traits<nonconst_iter >::value_type value_type; typedef typename std::iterator_traits<nonconst_iter >::difference_type difference_type; typedef typename std::iterator_traits<nonconst_iter >::pointer pointer; typedef typename std::iterator_traits<nonconst_iter >::reference reference; typedef Iterator base; typedef Iterator_T< nonconst_iter > self_type; protected: virtual bool equal (const ConstIterator &iter) const { const self_type *iters = dynamic_cast<const self_type *>(&iter); if (iters) { return (current == iters->get_current()); } else { throw std::invalid_argument("bad iterator type"); } } virtual ptrdiff_t distance(const ConstIterator &iter) const { const self_type *iters = dynamic_cast<const self_type *>(&iter); if (iters) { return std::distance(current, iters->get_current()); } else { throw std::invalid_argument("bad iterator type"); } } virtual Iterator* advance(ptrdiff_t n) { std::advance( current, n ); return this; } public: Iterator_T(nonconst_iter curr, VALUE seq = Qnil) : Iterator(seq), current(curr) { } const nonconst_iter& get_current() const { return current; } self_type& operator=( const self_type& b ) { base::operator=( b ); return *this; } self_type& operator=( const value_type& b ) { *current = b; return *this; } const value_type& operator*() const { return *current; } value_type& operator*() { return *current; } virtual VALUE inspect() const { VALUE ret = rb_str_new2("#<"); ret = rb_str_cat2( ret, rb_obj_classname(_seq) ); ret = rb_str_cat2( ret, "::iterator " ); VALUE cur = value(); ret = rb_str_concat( ret, rb_inspect(cur) ); ret = rb_str_cat2( ret, ">" ); return ret; } virtual VALUE to_s() const { VALUE ret = rb_str_new2( rb_obj_classname(_seq) ); ret = rb_str_cat2( ret, "::iterator " ); VALUE cur = value(); ret = rb_str_concat( ret, rb_obj_as_string(cur) ); return ret; } protected: nonconst_iter current; }; /** * Auxiliary functor to store the value of a ruby object inside * a reference of a compatible C++ type. ie: Ruby -> C++ * */ template <class ValueType> struct asval_oper { typedef ValueType value_type; typedef bool result_type; bool operator()(VALUE obj, value_type& v) const { return ( swig::asval< value_type >(obj, &v) == SWIG_OK ); } }; /** * Auxiliary functor to return a ruby object from a C++ type. * ie: C++ -> Ruby * */ template <class ValueType> struct from_oper { typedef const ValueType& argument_type; typedef VALUE result_type; result_type operator()(argument_type v) const { return swig::from(v); } }; /** * ConstIterator class for a const_iterator with no end() boundaries. * */ template<typename OutConstIterator, typename ValueType = typename std::iterator_traits<OutConstIterator>::value_type, typename FromOper = from_oper<ValueType> > class ConstIteratorOpen_T : public ConstIterator_T<OutConstIterator> { public: FromOper from; typedef OutConstIterator const_iter; typedef ValueType value_type; typedef ConstIterator_T<const_iter> base; typedef ConstIteratorOpen_T<OutConstIterator, ValueType, FromOper> self_type; ConstIteratorOpen_T(const_iter curr, VALUE seq = Qnil) : ConstIterator_T<OutConstIterator>(curr, seq) { } virtual VALUE value() const { return from(static_cast<const value_type&>(*(base::current))); } ConstIterator *dup() const { return new self_type(*this); } }; /** * Iterator class for an iterator with no end() boundaries. * */ template<typename InOutIterator, typename ValueType = typename std::iterator_traits<InOutIterator>::value_type, typename FromOper = from_oper<ValueType>, typename AsvalOper = asval_oper<ValueType> > class IteratorOpen_T : public Iterator_T<InOutIterator> { public: FromOper from; AsvalOper asval; typedef InOutIterator nonconst_iter; typedef ValueType value_type; typedef Iterator_T<nonconst_iter> base; typedef IteratorOpen_T<InOutIterator, ValueType, FromOper, AsvalOper> self_type; public: IteratorOpen_T(nonconst_iter curr, VALUE seq = Qnil) : Iterator_T<InOutIterator>(curr, seq) { } virtual VALUE value() const { return from(static_cast<const value_type&>(*(base::current))); } virtual VALUE setValue( const VALUE& v ) { value_type& dst = *base::current; if ( asval(v, dst) ) return v; return Qnil; } Iterator *dup() const { return new self_type(*this); } }; /** * ConstIterator class for a const_iterator where begin() and end() boundaries are known. * */ template<typename OutConstIterator, typename ValueType = typename std::iterator_traits<OutConstIterator>::value_type, typename FromOper = from_oper<ValueType> > class ConstIteratorClosed_T : public ConstIterator_T<OutConstIterator> { public: FromOper from; typedef OutConstIterator const_iter; typedef ValueType value_type; typedef ConstIterator_T<const_iter> base; typedef ConstIteratorClosed_T<OutConstIterator, ValueType, FromOper> self_type; protected: virtual ConstIterator* advance(ptrdiff_t n) { std::advance( base::current, n ); if ( base::current == end ) throw stop_iteration(); return this; } public: ConstIteratorClosed_T(const_iter curr, const_iter first, const_iter last, VALUE seq = Qnil) : ConstIterator_T<OutConstIterator>(curr, seq), begin(first), end(last) { } virtual VALUE value() const { if (base::current == end) { throw stop_iteration(); } else { return from(static_cast<const value_type&>(*(base::current))); } } ConstIterator *dup() const { return new self_type(*this); } private: const_iter begin; const_iter end; }; /** * Iterator class for a iterator where begin() and end() boundaries are known. * */ template<typename InOutIterator, typename ValueType = typename std::iterator_traits<InOutIterator>::value_type, typename FromOper = from_oper<ValueType>, typename AsvalOper = asval_oper<ValueType> > class IteratorClosed_T : public Iterator_T<InOutIterator> { public: FromOper from; AsvalOper asval; typedef InOutIterator nonconst_iter; typedef ValueType value_type; typedef Iterator_T<nonconst_iter> base; typedef IteratorClosed_T<InOutIterator, ValueType, FromOper, AsvalOper> self_type; protected: virtual Iterator* advance(ptrdiff_t n) { std::advance( base::current, n ); if ( base::current == end ) throw stop_iteration(); return this; } public: IteratorClosed_T(nonconst_iter curr, nonconst_iter first, nonconst_iter last, VALUE seq = Qnil) : Iterator_T<InOutIterator>(curr, seq), begin(first), end(last) { } virtual VALUE value() const { if (base::current == end) { throw stop_iteration(); } else { return from(static_cast<const value_type&>(*(base::current))); } } // Iterator setter method, required by Ruby virtual VALUE setValue( const VALUE& v ) { if (base::current == end) throw stop_iteration(); value_type& dst = *base::current; if ( asval( v, dst ) ) return v; return Qnil; } Iterator *dup() const { return new self_type(*this); } private: nonconst_iter begin; nonconst_iter end; }; /* Partial specialization for bools which don't allow de-referencing */ template< typename InOutIterator, typename FromOper, typename AsvalOper > class IteratorOpen_T< InOutIterator, bool, FromOper, AsvalOper > : public Iterator_T<InOutIterator> { public: FromOper from; AsvalOper asval; typedef InOutIterator nonconst_iter; typedef bool value_type; typedef Iterator_T<nonconst_iter> base; typedef IteratorOpen_T<InOutIterator, bool, FromOper, AsvalOper> self_type; IteratorOpen_T(nonconst_iter curr, VALUE seq = Qnil) : Iterator_T<InOutIterator>(curr, seq) { } virtual VALUE value() const { return from(static_cast<const value_type&>(*(base::current))); } virtual VALUE setValue( const VALUE& v ) { bool tmp = *base::current; if ( asval( v, tmp ) ) { *base::current = tmp; return v; } return Qnil; } Iterator *dup() const { return new self_type(*this); } }; /* Partial specialization for bools which don't allow de-referencing */ template< typename InOutIterator, typename FromOper, typename AsvalOper > class IteratorClosed_T< InOutIterator, bool, FromOper, AsvalOper > : public Iterator_T<InOutIterator> { public: FromOper from; AsvalOper asval; typedef InOutIterator nonconst_iter; typedef bool value_type; typedef Iterator_T<nonconst_iter> base; typedef IteratorClosed_T<InOutIterator, bool, FromOper, AsvalOper> self_type; protected: virtual Iterator* advance(ptrdiff_t n) { std::advance( base::current, n ); if ( base::current == end ) throw stop_iteration(); return this; } public: IteratorClosed_T(nonconst_iter curr, nonconst_iter first, nonconst_iter last, VALUE seq = Qnil) : Iterator_T<InOutIterator>(curr, seq), begin(first), end(last) { } virtual VALUE value() const { if (base::current == end) { throw stop_iteration(); } else { return from(static_cast<const value_type&>(*(base::current))); } } virtual VALUE setValue( const VALUE& v ) { if (base::current == end) throw stop_iteration(); bool tmp = *base::current; if ( asval( v, tmp ) ) { *base::current = tmp; return v; } return Qnil; } Iterator *dup() const { return new self_type(*this); } private: nonconst_iter begin; nonconst_iter end; }; /** * Helper function used to wrap a bounded const_iterator. This is to be used in * a %typemap(out), for example. * */ template<typename InOutIter> inline Iterator* make_nonconst_iterator(const InOutIter& current, const InOutIter& begin, const InOutIter& end, VALUE seq = Qnil) { return new IteratorClosed_T<InOutIter>(current, begin, end, seq); } /** * Helper function used to wrap an unbounded const_iterator. This is to be used in * a %typemap(out), for example. * */ template<typename InOutIter> inline Iterator* make_nonconst_iterator(const InOutIter& current, VALUE seq = Qnil) { return new IteratorOpen_T<InOutIter>(current, seq); } /** * Helper function used to wrap a bounded const_iterator. This is to be used in * a %typemap(out), for example. * */ template<typename OutIter> inline ConstIterator* make_const_iterator(const OutIter& current, const OutIter& begin, const OutIter& end, VALUE seq = Qnil) { return new ConstIteratorClosed_T<OutIter>(current, begin, end, seq); } /** * Helper function used to wrap an unbounded const_iterator. This is to be used in * a %typemap(out), for example. * */ template<typename OutIter> inline ConstIterator* make_const_iterator(const OutIter& current, VALUE seq = Qnil) { return new ConstIteratorOpen_T<OutIter>(current, seq); } } } %fragment("ConstIterator"); // // This part is just so SWIG is aware of the base abstract iterator class. // namespace swig { /* Throw a StopIteration exception */ %ignore stop_iteration; struct stop_iteration {}; %typemap(throws) stop_iteration { (void)$1; SWIG_Ruby_ExceptionType(NULL, Qnil); SWIG_fail; } /* Mark methods that return new objects */ %newobject ConstIterator::dup; %newobject ConstIterator::operator + (ptrdiff_t n) const; %newobject ConstIterator::operator - (ptrdiff_t n) const; %nodirector ConstIterator; %catches(swig::stop_iteration) ConstIterator::value() const; %catches(swig::stop_iteration) ConstIterator::incr(size_t n = 1); %catches(swig::stop_iteration) ConstIterator::decr(size_t n = 1); %catches(std::invalid_argument) ConstIterator::distance(const ConstIterator &x) const; %catches(std::invalid_argument) ConstIterator::equal (const ConstIterator &x) const; %catches(swig::stop_iteration) ConstIterator::next(); %catches(swig::stop_iteration) ConstIterator::previous(); %catches(swig::stop_iteration) ConstIterator::advance(ptrdiff_t n); %catches(swig::stop_iteration) ConstIterator::operator += (ptrdiff_t n); %catches(swig::stop_iteration) ConstIterator::operator -= (ptrdiff_t n); %catches(swig::stop_iteration) ConstIterator::operator + (ptrdiff_t n) const; %catches(swig::stop_iteration) ConstIterator::operator - (ptrdiff_t n) const; struct ConstIterator { protected: ConstIterator(VALUE seq); public: virtual ~ConstIterator(); // Access iterator method, required by Ruby virtual VALUE value() const; // C++ common/needed methods virtual ConstIterator *dup() const; virtual VALUE inspect() const; virtual VALUE to_s() const; virtual ConstIterator* next(size_t n = 1); virtual ConstIterator* previous(size_t n = 1); bool operator == (const ConstIterator& x) const; ConstIterator* operator + (ptrdiff_t n) const; ConstIterator* operator - (ptrdiff_t n) const; ptrdiff_t operator - (const ConstIterator& x) const; }; struct Iterator : public ConstIterator { %rename("value=") setValue( const VALUE& v ); virtual VALUE setValue( const VALUE& v ); virtual Iterator *dup() const; virtual Iterator* next(size_t n = 1); virtual Iterator* previous(size_t n = 1); virtual VALUE inspect() const; virtual VALUE to_s() const; bool operator == (const Iterator& x) const; Iterator* operator + (ptrdiff_t n) const; Iterator* operator - (ptrdiff_t n) const; ptrdiff_t operator - (const Iterator& x) const; }; }