|
Boost : |
From: David Abrahams (abrahams_at_[hidden])
Date: 2000-11-29 23:01:36
Ullrich,
it would be great if you could find a way to keep a reference to the
container alive as long as the cursor was in existence. Otherwise, the user
risks crashing from Python because of a dangling reference.
-Dave
----- Original Message -----
From: "Ullrich Koethe" <koethe_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Wednesday, November 29, 2000 4:09 PM
Subject: Re: [boost] py_cpp and vector<..>::const_iterator
> Anton Gluck wrote:
> >
> > Ullrich,
> >
> > On Mon, 27 Nov 2000, Ullrich Koethe wrote:
> >
> > > Petr Kocmid wrote:
> > > >
> > > > > Don't expose iterators. Python has its own iteration idioms (e.g.
> > > > > "for x in
> > > > > S"), so just support the python sequence interface on your vector.
Since
> > > > > your vector is a random-access container, this will be fast. I
reccommend
> > > > > this approach.
> > > >
> > > > I predict the problem Anton had will arise many times in the future.
Perhaps
> > > > we can
> > > > add some generic conversion of STL containers to sequence/mapping
protocol
> > > > to py_cpp.
> > > >
> > >
> > >
> > > I've implemented and successfully tested the following
"Cursor"-feature
> > > to wrap STL iterators:
> > >
> > > in C++:
> > >
> > > typedef std::list<Foo> FooList;
> > > boost::python::class_builder<FooList> foolist_class(my_module,
> > > "FooList");
> > > foolist_class.def(boost::python::constructor<>());
> > > foolist_class.def((void (FooList::*)(Foo const
> > > &))&FooList::push_back, "append");
> > >
> > > // define a cursor for FooLists
> > > my_module.def_cursor_for(foolist_class);
> > >
> > > Then in Python:
> > >
> > > >>> fooList = FooList()
> > > >>> fooList.append(Foo(1))
> > > >>> fooList.append(Foo(2))
> > > >>>
> > > >>> for i in fooList.cusor(): # use cursor in a loop
> > > ... i
> > > ... print i.getData()
> > > ...
> > > <Foo object at 111070>
> > > 1
> > > <Foo object at 1110e8>
> > > 2
> > > >>>
> > > >>> c = fooList.cursor()
> > > >>> c[1].getData() # use cursor to read and write the data
> > > 2
> > > >>> c[1] = Foo(4)
> > > >>> c[1].getData()
> > > 4
> > >
> > > Would this suit your needs ?
> >
> > I'm not sure if this was meant for me or Petr. I can see useful parts
> > here when creating an iterator, but can't see how it helps exposing an
> > existing iterator. I guess the magic is happening in
> > "my_module.def_cursor_for(foolist_class);"?
> >
>
> Sorry for being too vague. It was meant for you and Petr (and anyone
> interested in wrapping iterators).
>
> Yes, the magic is happening in
> my_module.def_cursor_for(foolist_class);". This line creates an
> auxiliary class "FooList_cursor" that wraps FooList's iterator. In
> addition, it adds the factory function "cursor()" to extension class
> "FooList" itself.
>
> The auxiliary cursor class can be created for *any STL conforming
> container* (code attached below). In particular, the following is
> needed:
>
> FooList::iterator
> FooList::value_type
> FooList::begin()
> FooList::size()
> std::iterator_traits<FooList::iterator>::iterator_category
>
> The cursor implements random access functions (get_item() and
> set_item()) for any iterator, but these will only be as efficient as the
> underlying iterator allows. However, this is not a problem because 'for
> i in fooList.cusor():' accesses the items in forward order anyway. Only
> problem: I don't know how MSVC distinguishes iterator categories, so on
> this compiler everything is treated as a forward iterator. Any hints?
>
> Regards
> Ulli
>
> template <class Container>
> struct cursor
> {
> typedef typename Container::iterator iterator;
> typedef typename Container::value_type value_type;
> typedef typename iterator_traits<iterator>::iterator_category
> iterator_category;
>
> cursor(Container & c)
> : m_begin(c.begin()),
> m_iter(c.begin()),
> m_size(c.size()),
> m_index(0)
> {}
>
> void advance(int index, std::forward_iterator_tag)
> {
> if(index < 0 || index >= m_size)
> {
> PyErr_SetObject(PyExc_KeyError,
> BOOST_PYTHON_CONVERSION::to_python(index));
> throw python::error_already_set();
> }
>
> int delta = index - m_index;
> if(delta < 0)
> {
> m_iter = m_begin;
> delta = index;
> }
> std::advance(m_iter, delta);
> m_index = index;
> }
>
> void advance(int index, std::bidirectional_iterator_tag)
> {
> if(index < 0 || index >= m_size)
> {
> PyErr_SetObject(PyExc_KeyError,
> BOOST_PYTHON_CONVERSION::to_python(index));
> throw python::error_already_set();
> }
> int delta = index - m_index;
> std::advance(m_iter, delta);
> m_index = index;
> }
>
> value_type const & get_item(int index)
> {
> advance(index, iterator_category());
> return *m_iter;
> }
>
> void set_item(int index, value_type const & v)
> {
> advance(index, iterator_category());
> *m_iter = v;
> }
>
> int len() const
> { return m_size; }
>
> iterator m_begin, m_iter;
> int m_index, m_size;
> };
>
>
> --
> ________________________________________________________________
> | |
> | Ullrich Koethe Universität Hamburg / University of Hamburg |
> | FB Informatik / Dept. of Computer Science |
> | AB Kognitive Systeme / Cognitive Systems Group |
> | |
> | Phone: +49 (0)40 42883-2573 Vogt-Koelln-Str. 30 |
> | Fax: +49 (0)40 42883-2572 D - 22527 Hamburg |
> | Email: u.koethe_at_[hidden] Germany |
> | koethe_at_[hidden] |
> | WWW: http://kogs-www.informatik.uni-hamburg.de/~koethe/ |
> |________________________________________________________________|
>
>
>
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk