mirror of
https://github.com/boostorg/python.git
synced 2026-01-28 07:22:31 +00:00
added the cursor feature
[SVN r8368]
This commit is contained in:
@@ -144,7 +144,27 @@ class class_builder
|
||||
reference<detail::extension_class<T, U> > m_class;
|
||||
};
|
||||
|
||||
// The bug mentioned at the top of this file is that on certain compilers static
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// helper function that does the actual work of creating a cursor for a n
|
||||
// STL conforming container. called by module_builder::def_cursor_for()
|
||||
template <class T, class U>
|
||||
void wrap_cursor_class(module_builder & module,
|
||||
class_builder<T, U> & wrapped_container)
|
||||
{
|
||||
std::string cursor_name(wrapped_container.get_extension_class()->tp_name);
|
||||
cursor_name += "_cursor";
|
||||
class_builder<cursor<T> > cursor_class(module, cursor_name.c_str());
|
||||
|
||||
cursor_class.def(&cursor<T>::get_item, "__getitem__");
|
||||
cursor_class.def(&cursor<T>::set_item, "__setitem__");
|
||||
cursor_class.def(&cursor<T>::len, "__len__");
|
||||
wrapped_container.def(&extension_class_cursor_factory<T>::get, "cursor");
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// global functions declared within the body of a class template will only be
|
||||
// generated when the class template is constructed, and when (for some reason)
|
||||
// the construction does not occur via a new-expression. Otherwise, we could
|
||||
|
||||
@@ -319,6 +319,98 @@ class read_only_setattr_function : public function
|
||||
string m_name;
|
||||
};
|
||||
|
||||
|
||||
/* helper class to wrap STL conforming iterators.
|
||||
|
||||
Given a wrapped container ("FooList", say), this template is used to create
|
||||
an auxiliary class "FooList_cursor" that wraps the container's iterator.
|
||||
The cursor can be used in Python loops likes this:
|
||||
|
||||
>>> for i in foo_list.cursor():
|
||||
... print i.get_data()
|
||||
|
||||
The auxiliary cursor class can be created for any STL conforming
|
||||
container. It 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
|
||||
the above Python loop accesses the items in forward order anyway.
|
||||
*/
|
||||
template <class Container>
|
||||
struct cursor
|
||||
{
|
||||
typedef typename Container::iterator iterator;
|
||||
typedef typename Container::value_type value_type;
|
||||
|
||||
cursor(Container & c, ref python_object)
|
||||
: m_python_object(python_object),
|
||||
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, std::iterator_category(m_iter));
|
||||
return *m_iter;
|
||||
}
|
||||
|
||||
void set_item(int index, value_type const & v)
|
||||
{
|
||||
advance(index, std::iterator_category(m_iter));
|
||||
*m_iter = v;
|
||||
}
|
||||
|
||||
int len() const
|
||||
{ return m_size; }
|
||||
|
||||
ref m_python_object;
|
||||
iterator m_begin, m_iter;
|
||||
int m_index, m_size;
|
||||
};
|
||||
|
||||
/* create a cursor for an STL conforming container */
|
||||
template <class T>
|
||||
struct extension_class_cursor_factory
|
||||
{
|
||||
static cursor<T> get(ref container)
|
||||
{
|
||||
return cursor<T>(
|
||||
BOOST_PYTHON_CONVERSION::from_python(container.get(), type<T&>()),
|
||||
container);
|
||||
}
|
||||
};
|
||||
|
||||
template <class From, class To>
|
||||
struct define_conversion
|
||||
{
|
||||
|
||||
@@ -16,6 +16,17 @@
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
class module_builder;
|
||||
|
||||
template <class T, class U> class class_builder;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
void wrap_cursor_class(module_builder & module,
|
||||
class_builder<T, U> & wrapped_container);
|
||||
} // namspace detail
|
||||
|
||||
class module_builder
|
||||
{
|
||||
public:
|
||||
@@ -39,6 +50,15 @@ class module_builder
|
||||
{
|
||||
add(detail::new_wrapped_function(fn), name);
|
||||
}
|
||||
|
||||
// wrapped_container must wrap an STL conforming container;
|
||||
// this function creates a cursor that wraps this container's iterator
|
||||
// and adds the factory function "cursor()" to the wrapped container
|
||||
template <class T, class U>
|
||||
void def_cursor_for(class_builder<T, U> & wrapped_container)
|
||||
{
|
||||
detail::wrap_cursor_class(*this, wrapped_container);
|
||||
}
|
||||
|
||||
// Return true iff a module is currently being built.
|
||||
static bool initializing();
|
||||
|
||||
Reference in New Issue
Block a user