ifndef Rice__detail__Iterator__hpp_ define Rice__detail__Iterator__hpp_

include “method_data.hpp” include “ruby.hpp” include “../protect.hpp” include “../Data_Object.hpp” include “../Identifier.hpp”

namespace Rice {

namespace detail {

class Iterator { public:

virtual ~Iterator() { }

virtual VALUE call_impl(VALUE self) = 0;

static VALUE call(VALUE self)
{
  VALUE data = (VALUE)method_data();
  Data_Object<Iterator> iterator(
      data,
      Data_Type<Iterator>());
  return iterator->call_impl(self);
}

};

template<typename T, typename Iterator_T> class Iterator_Impl

: public Iterator

{ public:

Iterator_Impl(
    Iterator_T (T::*begin)(),
    Iterator_T (T::*end)(),
    Data_Type<T> data_type)
  : begin_(begin)
  , end_(end)
  , data_type_(data_type)
{
}

virtual VALUE call_impl(VALUE self)
{
  Data_Object<T> obj(self, data_type_);
  Iterator_T it = obj->begin();
  Iterator_T end = obj->end();
  for(; it != end; ++it)
  {
    Rice::protect(rb_yield, to_ruby(*it));
  }
  return self;
}

private:

Iterator_T (T::*begin_)();
Iterator_T (T::*end_)();
Data_Type<T> data_type_;

};

template<typename T, typename Iterator_T> void define_iterator(

Module klass,
Identifier name,
Iterator_T (T::*begin)(),
Iterator_T (T::*end)())

{

Data_Type<Iterator> iterator_klass;
Data_Object<Iterator> iterator(
    new Iterator_Impl<T, Iterator_T>(
        begin,
        end,
        Data_Type<T>(klass)),
    iterator_klass);
define_method_with_data(
    klass,
    name,
    (RUBY_METHOD_FUNC)iterator->call,
    0,
    iterator);

}

} // namespace detail

} // namespace Rice

endif // Rice__detail__Iterator__hpp_