Iterators for heterogeneous container

View: New views
5 Messages — Rating Filter:   Alert me  

Iterators for heterogeneous container

by Thomas Daniel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I am having trouble wrapping a container that can hold multiple object
types and therefore has multiple iterator types.

My C++ library has these classes:

class Tomato;
class Potato;
class Garden {
    Iter<Tomato>   get_tomatoes();
    Iter<Potato>   get_potatoes();
};

template<class T>
class Iter {
    T get_next();
};

which allows to write:

Iter<Potato> potatoes = garden.get_potatoes();
while (Potato potato = potatoes.get_next()) {
   cout << potato.name();
}

I am trying to use boost to wrap it so that I can write in python:

for potato in garden.get_potatoes():
   print potato.name()

Any pointers how to achieve this with boost?





_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@...
http://mail.python.org/mailman/listinfo/cplusplus-sig

Re: Iterators for heterogeneous container

by Michele De Stefano :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thomas,

I think the answer is here:
http://www.boost.org/doc/libs/1_40_0/libs/python/doc/tutorial/doc/html/python/iterators.html

but you should modify your "Garden" class in order to support "begin"
and "end" iterators for "tomatoes" and "potatoes".

With these modifications:

class Garden {
public:
  typedef ....      Tomato_Iter;
  typedef ....      Potato_Iter;

  Tomato_Iter   tomatoes_begin();
  Tomato_Iter   tomatoes_end();
  Potato_Iter   potatoes_begin();
  Potato_Iter   potatoes_end();
};

you can expose your Garden class as here:

class_<Garden>("Garden")
    .property("tomatoes", range(&Garden::tomatoes_begin, &Garden::tomatoes_end))
    .property("potatoes", range(&Garden::potatoes_begin,
&Garden::potatoes_end));

At this point, in Python, you should be able to write:

for potato in garden.potatoes:
   .... and do here whatever you want ...

It's the best I can suggest


2009/11/6 Thomas Daniel <thomasd57@...>:

> I am having trouble wrapping a container that can hold multiple object types
> and therefore has multiple iterator types.
>
> My C++ library has these classes:
>
> class Tomato;
> class Potato;
> class Garden {
>   Iter<Tomato>   get_tomatoes();
>   Iter<Potato>   get_potatoes();
> };
>
> template<class T>
> class Iter {
>   T get_next();
> };
>
> which allows to write:
>
> Iter<Potato> potatoes = garden.get_potatoes();
> while (Potato potato = potatoes.get_next()) {
>  cout << potato.name();
> }
>
> I am trying to use boost to wrap it so that I can write in python:
>
> for potato in garden.get_potatoes():
>  print potato.name()
>
> Any pointers how to achieve this with boost?
>
>
>
>
>
> _______________________________________________
> Cplusplus-sig mailing list
> Cplusplus-sig@...
> http://mail.python.org/mailman/listinfo/cplusplus-sig
>



--
Michele De Stefano
http://www.linkedin.com/in/micdestefano
http://xoomer.virgilio.it/michele_de_stefano
http://code.google.com/p/mds-utils
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@...
http://mail.python.org/mailman/listinfo/cplusplus-sig

Re: Iterators for heterogeneous container

by Thomas Daniel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Michele,

Thanks for the pointers, but unfortunately I don't think they apply in
my case. It seems that boost support for iterators was written *only*
with STL-like iterators in mind. You have to have begin() and end() and
to be able to dereference the iterator. I can't do it (or I don't know
how to do it).
In contrast, my iterators are more like python iteration sequence, with
only one method: get_next(), which returns the next object in the
container *and* advances the iterator at the same time. I can't  
dereference this iterator, as you would do in STL.

In fact, this seems to be so close to the python iteration model, that a
simple approach should be doable:

BOOST_PYTHON_MODULE(vegetables)
{
    class_<Garden>("Garden")
        .def("get_potatoes", &Garden::get_potatoes)
        .def("get_tomatoes", &Garden::get_tomatoes)
    ;
    class_<TomatoIter>("TomatoIter")
        .def("__iter__", &TomatoIter::get_next)
    ;
}

That at least compiles - unlike all my previous attempts that generate
three pages of template errors - but python complain:

TypeError: iter() returned non-iterator of type 'Tomato'

so now I am trying to figure out how to tell boost that get_tomatoes
returns an iterator ...

Thomas


Michele De Stefano wrote:

> Thomas,
>
> I think the answer is here:
> http://www.boost.org/doc/libs/1_40_0/libs/python/doc/tutorial/doc/html/python/iterators.html
>
> but you should modify your "Garden" class in order to support "begin"
> and "end" iterators for "tomatoes" and "potatoes".
>
> With these modifications:
>
> class Garden {
> public:
>   typedef ....      Tomato_Iter;
>   typedef ....      Potato_Iter;
>
>   Tomato_Iter   tomatoes_begin();
>   Tomato_Iter   tomatoes_end();
>   Potato_Iter   potatoes_begin();
>   Potato_Iter   potatoes_end();
> };
>
> you can expose your Garden class as here:
>
> class_<Garden>("Garden")
>     .property("tomatoes", range(&Garden::tomatoes_begin, &Garden::tomatoes_end))
>     .property("potatoes", range(&Garden::potatoes_begin,
> &Garden::potatoes_end));
>
> At this point, in Python, you should be able to write:
>
> for potato in garden.potatoes:
>    .... and do here whatever you want ...
>
> It's the best I can suggest
>
>
> 2009/11/6 Thomas Daniel <thomasd57@...>:
>  
>> I am having trouble wrapping a container that can hold multiple object types
>> and therefore has multiple iterator types.
>>
>> My C++ library has these classes:
>>
>> class Tomato;
>> class Potato;
>> class Garden {
>>   Iter<Tomato>   get_tomatoes();
>>   Iter<Potato>   get_potatoes();
>> };
>>
>> template<class T>
>> class Iter {
>>   T get_next();
>> };
>>
>> which allows to write:
>>
>> Iter<Potato> potatoes = garden.get_potatoes();
>> while (Potato potato = potatoes.get_next()) {
>>  cout << potato.name();
>> }
>>
>> I am trying to use boost to wrap it so that I can write in python:
>>
>> for potato in garden.get_potatoes():
>>  print potato.name()
>>
>> Any pointers how to achieve this with boost?
>>
>>
>>
>>
>>
>> _______________________________________________
>> Cplusplus-sig mailing list
>> Cplusplus-sig@...
>> http://mail.python.org/mailman/listinfo/cplusplus-sig
>>
>>    
>
>
>
>  
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@...
http://mail.python.org/mailman/listinfo/cplusplus-sig

Re: Iterators for heterogeneous container

by troy d. straszheim :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thomas Daniel wrote:

>
> BOOST_PYTHON_MODULE(vegetables)
> {
>    class_<Garden>("Garden")
>        .def("get_potatoes", &Garden::get_potatoes)
>        .def("get_tomatoes", &Garden::get_tomatoes)
>    ;
>    class_<TomatoIter>("TomatoIter")
>        .def("__iter__", &TomatoIter::get_next)
>    ;
> }
>
> That at least compiles - unlike all my previous attempts that generate
> three pages of template errors - but python complain:
>
> TypeError: iter() returned non-iterator of type 'Tomato'
>
> so now I am trying to figure out how to tell boost that get_tomatoes
> returns an iterator ...
>

Please don't top-post, guys

As you know, python iterators have a function next() that returns the
next object in the iteree, or throw StopIteration when they're at the
end.  As you also know, python expects member functions __iter__() to
return an iterator.  Is the thing returned by TomatoIter::get_next an
iterator, ie does it implement the iterator interface?

-t

_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@...
http://mail.python.org/mailman/listinfo/cplusplus-sig

Re: Iterators for heterogeneous container

by Thomas Daniel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



troy d. straszheim wrote:

> Thomas Daniel wrote:
>>
>> BOOST_PYTHON_MODULE(vegetables)
>> {
>>    class_<Garden>("Garden")
>>        .def("get_potatoes", &Garden::get_potatoes)
>>        .def("get_tomatoes", &Garden::get_tomatoes)
>>    ;
>>    class_<TomatoIter>("TomatoIter")
>>        .def("__iter__", &TomatoIter::get_next)
>>    ;
>> }
>>
>> That at least compiles - unlike all my previous attempts that
>> generate three pages of template errors - but python complain:
>>
>> TypeError: iter() returned non-iterator of type 'Tomato'
>>
>> so now I am trying to figure out how to tell boost that get_tomatoes
>> returns an iterator ...
>>
>
> Please don't top-post, guys
>
> As you know, python iterators have a function next() that returns the
> next object in the iteree, or throw StopIteration when they're at the
> end.  As you also know, python expects member functions __iter__() to
> return an iterator.  Is the thing returned by TomatoIter::get_next an
> iterator, ie does it implement the iterator interface?
>
> -t
>
>
Thank you very much for the email, you did put me on the right track and
I finally figured out how to do it, with help from here also:
http://wiki.python.org/moin/boost.python/iterator

The solution involves creating a wrapper class around get_next(), which
throws StopIteration when done and a "pass_through" function to bind to
__iter__:

inline TomatoIter pass_through(const TomatoIter& iter) { return iter; }

Tomato next(TomatoIter& iter) {
    Tomato tomato = iter.get_next();
    if (!tomato) {
        PyErr_SetString(PyExc_StopIteration, "No more data.");
        throw_error_already_set();
    }
    return tomato;
}

Now, I can do this:
BOOST_PYTHON_MODULE(Garden)
{  
     ......
    class_<TomatoIter>("TomatoIter", no_init)
        .def("next", next)
        .def("__iter__", pass_through)
    ;

and it works.

Thomas

_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@...
http://mail.python.org/mailman/listinfo/cplusplus-sig