Boost logo

Boost :

From: Ullrich Koethe (koethe_at_[hidden])
Date: 2000-11-29 16:09:18


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