summaryrefslogtreecommitdiff
path: root/boost/python/suite/indexing
diff options
context:
space:
mode:
Diffstat (limited to 'boost/python/suite/indexing')
-rw-r--r--boost/python/suite/indexing/container_utils.hpp57
-rw-r--r--boost/python/suite/indexing/detail/indexing_suite_detail.hpp759
-rw-r--r--boost/python/suite/indexing/indexing_suite.hpp299
-rw-r--r--boost/python/suite/indexing/map_indexing_suite.hpp181
-rw-r--r--boost/python/suite/indexing/vector_indexing_suite.hpp242
5 files changed, 1538 insertions, 0 deletions
diff --git a/boost/python/suite/indexing/container_utils.hpp b/boost/python/suite/indexing/container_utils.hpp
new file mode 100644
index 0000000000..72710bb8b0
--- /dev/null
+++ b/boost/python/suite/indexing/container_utils.hpp
@@ -0,0 +1,57 @@
+
+// (C) Copyright Joel de Guzman 2003.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef PY_CONTAINER_UTILS_JDG20038_HPP
+# define PY_CONTAINER_UTILS_JDG20038_HPP
+
+# include <utility>
+# include <boost/foreach.hpp>
+# include <boost/python/object.hpp>
+# include <boost/python/handle.hpp>
+# include <boost/python/extract.hpp>
+# include <boost/python/stl_iterator.hpp>
+
+namespace boost { namespace python { namespace container_utils {
+
+ template <typename Container>
+ void
+ extend_container(Container& container, object l)
+ {
+ typedef typename Container::value_type data_type;
+
+ // l must be iterable
+ BOOST_FOREACH(object elem,
+ std::make_pair(
+ boost::python::stl_input_iterator<object>(l),
+ boost::python::stl_input_iterator<object>()
+ ))
+ {
+ extract<data_type const&> x(elem);
+ // try if elem is an exact data_type type
+ if (x.check())
+ {
+ container.push_back(x());
+ }
+ else
+ {
+ // try to convert elem to data_type type
+ extract<data_type> x(elem);
+ if (x.check())
+ {
+ container.push_back(x());
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "Incompatible Data Type");
+ throw_error_already_set();
+ }
+ }
+ }
+ }
+
+}}} // namespace boost::python::container_utils
+
+#endif
diff --git a/boost/python/suite/indexing/detail/indexing_suite_detail.hpp b/boost/python/suite/indexing/detail/indexing_suite_detail.hpp
new file mode 100644
index 0000000000..70df8a7273
--- /dev/null
+++ b/boost/python/suite/indexing/detail/indexing_suite_detail.hpp
@@ -0,0 +1,759 @@
+// (C) Copyright Joel de Guzman 2003.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef INDEXING_SUITE_DETAIL_JDG20036_HPP
+# define INDEXING_SUITE_DETAIL_JDG20036_HPP
+
+# include <boost/python/extract.hpp>
+# include <boost/scoped_ptr.hpp>
+# include <boost/get_pointer.hpp>
+# include <boost/detail/binary_search.hpp>
+# include <boost/numeric/conversion/cast.hpp>
+# include <boost/type_traits/is_pointer.hpp>
+# include <vector>
+# include <map>
+#include <iostream>
+
+namespace boost { namespace python { namespace detail {
+
+#if defined(NDEBUG)
+#define BOOST_PYTHON_INDEXING_CHECK_INVARIANT
+#else
+#define BOOST_PYTHON_INDEXING_CHECK_INVARIANT check_invariant()
+#endif
+
+ template <class Proxy>
+ struct compare_proxy_index
+ {
+ // This functor compares a proxy and an index.
+ // This is used by proxy_group::first_proxy to
+ // get first proxy with index i.
+
+ template <class Index>
+ bool operator()(PyObject* prox, Index i) const
+ {
+ typedef typename Proxy::policies_type policies_type;
+ Proxy& proxy = extract<Proxy&>(prox)();
+ return policies_type::
+ compare_index(proxy.get_container(), proxy.get_index(), i);
+ }
+ };
+
+ // The proxy_group class holds a vector of container element
+ // proxies. First, what is a container element proxy? A container
+ // element proxy acts like a smart pointer holding a reference to
+ // a container and an index (see container_element, for details).
+ //
+ // The proxies are held in a vector always sorted by its index.
+ // Various functions manage the addition, removal and searching
+ // of proxies from the vector.
+ //
+ template <class Proxy>
+ class proxy_group
+ {
+ public:
+
+ typedef typename std::vector<PyObject*>::const_iterator const_iterator;
+ typedef typename std::vector<PyObject*>::iterator iterator;
+ typedef typename Proxy::index_type index_type;
+ typedef typename Proxy::policies_type policies_type;
+
+ iterator
+ first_proxy(index_type i)
+ {
+ // Return the first proxy with index <= i
+ return boost::detail::lower_bound(
+ proxies.begin(), proxies.end(),
+ i, compare_proxy_index<Proxy>());
+ }
+
+ void
+ remove(Proxy& proxy)
+ {
+ // Remove a proxy
+ for (iterator iter = first_proxy(proxy.get_index());
+ iter != proxies.end(); ++iter)
+ {
+ if (&extract<Proxy&>(*iter)() == &proxy)
+ {
+ proxies.erase(iter);
+ break;
+ }
+ }
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ }
+
+ void
+ add(PyObject* prox)
+ {
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ // Add a proxy
+ proxies.insert(
+ first_proxy(extract<Proxy&>(prox)().get_index()), prox);
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ }
+
+ void
+ erase(index_type i, mpl::false_)
+ {
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ // Erase the proxy with index i
+ replace(i, i+1, 0);
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ }
+
+ void
+ erase(index_type i, mpl::true_)
+ {
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ // Erase the proxy with index i
+
+ iterator iter = first_proxy(i);
+ extract<Proxy&> p(*iter);
+
+ if (iter != proxies.end() && p().get_index() == i)
+ {
+ extract<Proxy&> p(*iter);
+ p().detach();
+ proxies.erase(iter);
+ }
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ }
+
+ void
+ erase(index_type from, index_type to)
+ {
+ // note: this cannot be called when container is not sliceable
+
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ // Erase all proxies with indexes from..to
+ replace(from, to, 0);
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ }
+
+ void
+ replace(
+ index_type from,
+ index_type to,
+ typename std::vector<PyObject*>::size_type len)
+ {
+ // note: this cannot be called when container is not sliceable
+
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ // Erase all proxies with indexes from..to.
+ // Adjust the displaced indexes such that the
+ // final effect is that we have inserted *len*
+ // number of proxies in the vacated region. This
+ // procedure involves adjusting the indexes of
+ // the proxies.
+
+ iterator left = first_proxy(from);
+ iterator right = proxies.end(); // we'll adjust this later
+
+ for (iterator iter = left; iter != right; ++iter)
+ {
+ if (extract<Proxy&>(*iter)().get_index() > to)
+ {
+ right = iter; // adjust right
+ break;
+ }
+ extract<Proxy&> p(*iter);
+ p().detach();
+ }
+
+ typename std::vector<PyObject*>::size_type
+ offset = left-proxies.begin();
+ proxies.erase(left, right);
+ right = proxies.begin()+offset;
+
+ while (right != proxies.end())
+ {
+ typedef typename Proxy::container_type::difference_type difference_type;
+ extract<Proxy&> p(*right);
+ p().set_index(
+ extract<Proxy&>(*right)().get_index()
+ - (difference_type(to) - from - len)
+ );
+
+ ++right;
+ }
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ }
+
+ PyObject*
+ find(index_type i)
+ {
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ // Find the proxy with *exact* index i.
+ // Return 0 (null) if no proxy with the
+ // given index is found.
+ iterator iter = first_proxy(i);
+ if (iter != proxies.end()
+ && extract<Proxy&>(*iter)().get_index() == i)
+ {
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ return *iter;
+ }
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ return 0;
+ }
+
+ typename std::vector<PyObject*>::size_type
+ size() const
+ {
+ BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
+ // How many proxies are there so far?
+ return proxies.size();
+ }
+
+ private:
+
+#if !defined(NDEBUG)
+ void
+ check_invariant() const
+ {
+ for (const_iterator i = proxies.begin(); i != proxies.end(); ++i)
+ {
+ if ((*i)->ob_refcnt <= 0)
+ {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Invariant: Proxy vector in an inconsistent state");
+ throw_error_already_set();
+ }
+
+ if (i+1 != proxies.end())
+ {
+ if (extract<Proxy&>(*(i+1))().get_index() ==
+ extract<Proxy&>(*(i))().get_index())
+ {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Invariant: Proxy vector in an inconsistent state (duplicate proxy)");
+ throw_error_already_set();
+ }
+ }
+ }
+ }
+#endif
+
+ std::vector<PyObject*> proxies;
+ };
+
+ // proxy_links holds a map of Container pointers (keys)
+ // with proxy_group(s) (data). Various functions manage
+ // the addition, removal and searching of proxies from
+ // the map.
+ //
+ template <class Proxy, class Container>
+ class proxy_links
+ {
+ public:
+
+ typedef std::map<Container*, proxy_group<Proxy> > links_t;
+ typedef typename Proxy::index_type index_type;
+
+ void
+ remove(Proxy& proxy)
+ {
+ // Remove a proxy.
+ typename links_t::iterator r = links.find(&proxy.get_container());
+ if (r != links.end())
+ {
+ r->second.remove(proxy);
+ if (r->second.size() == 0)
+ links.erase(r);
+ }
+ }
+
+ void
+ add(PyObject* prox, Container& container)
+ {
+ // Add a proxy
+ links[&container].add(prox);
+ }
+
+ template <class NoSlice>
+ void erase(Container& container, index_type i, NoSlice no_slice)
+ {
+ // Erase the proxy with index i
+ typename links_t::iterator r = links.find(&container);
+ if (r != links.end())
+ {
+ r->second.erase(i, no_slice);
+ if (r->second.size() == 0)
+ links.erase(r);
+ }
+ }
+
+ void
+ erase(Container& container, index_type from, index_type to)
+ {
+ // Erase all proxies with indexes from..to
+ typename links_t::iterator r = links.find(&container);
+ if (r != links.end())
+ {
+ r->second.erase(from, to);
+ if (r->second.size() == 0)
+ links.erase(r);
+ }
+ }
+
+ void
+ replace(
+ Container& container,
+ index_type from, index_type to, index_type len)
+ {
+ // Erase all proxies with indexes from..to.
+ // Adjust the displaced indexes such that the
+ // final effect is that we have inserted *len*
+ // number of proxies in the vacated region. This
+ // procedure involves adjusting the indexes of
+ // the proxies.
+
+ typename links_t::iterator r = links.find(&container);
+ if (r != links.end())
+ {
+ r->second.replace(from, to, len);
+ if (r->second.size() == 0)
+ links.erase(r);
+ }
+ }
+
+ PyObject*
+ find(Container& container, index_type i)
+ {
+ // Find the proxy with *exact* index i.
+ // Return 0 (null) if no proxy with the given
+ // index is found.
+ typename links_t::iterator r = links.find(&container);
+ if (r != links.end())
+ return r->second.find(i);
+ return 0;
+ }
+
+ private:
+
+ links_t links;
+ };
+
+ // container_element is our container proxy class.
+ // This class acts like a smart pointer to a container
+ // element. The class holds an index and a reference to
+ // a container. Dereferencing the smart pointer will
+ // retrieve the nth (index) element from the container.
+ //
+ // A container_element can also be detached from the
+ // container. In such a detached state, the container_element
+ // holds a copy of the nth (index) element, which it
+ // returns when dereferenced.
+ //
+ template <class Container, class Index, class Policies>
+ class container_element
+ {
+ public:
+
+ typedef Index index_type;
+ typedef Container container_type;
+ typedef typename Policies::data_type element_type;
+ typedef Policies policies_type;
+ typedef container_element<Container, Index, Policies> self_t;
+ typedef proxy_group<self_t> links_type;
+
+ container_element(object container, Index index)
+ : ptr()
+ , container(container)
+ , index(index)
+ {
+ }
+
+ container_element(container_element const& ce)
+ : ptr(ce.ptr.get() == 0 ? 0 : new element_type(*ce.ptr.get()))
+ , container(ce.container)
+ , index(ce.index)
+ {
+ }
+
+ ~container_element()
+ {
+ if (!is_detached())
+ get_links().remove(*this);
+ }
+
+ element_type& operator*() const
+ {
+ if (is_detached())
+ return *get_pointer(ptr);
+ return Policies::get_item(get_container(), index);
+ }
+
+ element_type* get() const
+ {
+ if (is_detached())
+ return get_pointer(ptr);
+ return &Policies::get_item(get_container(), index);
+ }
+
+ void
+ detach()
+ {
+ if (!is_detached())
+ {
+ ptr.reset(
+ new element_type(
+ Policies::get_item(get_container(), index)));
+ container = object(); // free container. reset it to None
+ }
+ }
+
+ bool
+ is_detached() const
+ {
+ return get_pointer(ptr) != 0;
+ }
+
+ Container&
+ get_container() const
+ {
+ return extract<Container&>(container)();
+ }
+
+ Index
+ get_index() const
+ {
+ return index;
+ }
+
+ void
+ set_index(Index i)
+ {
+ index = i;
+ }
+
+ static proxy_links<self_t, Container>&
+ get_links()
+ {
+ // All container_element(s) maintain links to
+ // its container in a global map (see proxy_links).
+ // This global "links" map is a singleton.
+
+ static proxy_links<self_t, Container> links;
+ return links; // singleton
+ }
+
+ private:
+
+ container_element& operator=(container_element const& ce);
+
+ scoped_ptr<element_type> ptr;
+ object container;
+ Index index;
+ };
+
+ template <
+ class Container
+ , class DerivedPolicies
+ , class ContainerElement
+ , class Index
+ >
+ struct no_proxy_helper
+ {
+ static void
+ register_container_element()
+ {
+ }
+
+ template <class DataType>
+ static object
+ base_get_item_helper(DataType const& p, mpl::true_)
+ {
+ return object(ptr(p));
+ }
+
+ template <class DataType>
+ static object
+ base_get_item_helper(DataType const& x, mpl::false_)
+ {
+ return object(x);
+ }
+
+ static object
+ base_get_item_(back_reference<Container&> const& container, PyObject* i)
+ {
+ return base_get_item_helper(
+ DerivedPolicies::get_item(
+ container.get(), DerivedPolicies::
+ convert_index(container.get(), i))
+ , is_pointer<BOOST_DEDUCED_TYPENAME Container::value_type>()
+ );
+ }
+
+ static void
+ base_replace_indexes(
+ Container& /*container*/, Index /*from*/,
+ Index /*to*/, Index /*n*/)
+ {
+ }
+
+ template <class NoSlice>
+ static void
+ base_erase_index(
+ Container& /*container*/, Index /*i*/, NoSlice /*no_slice*/)
+ {
+ }
+
+ static void
+ base_erase_indexes(Container& /*container*/, Index /*from*/, Index /*to*/)
+ {
+ }
+ };
+
+ template <
+ class Container
+ , class DerivedPolicies
+ , class ContainerElement
+ , class Index
+ >
+ struct proxy_helper
+ {
+ static void
+ register_container_element()
+ {
+ register_ptr_to_python<ContainerElement>();
+ }
+
+ static object
+ base_get_item_(back_reference<Container&> const& container, PyObject* i)
+ {
+ // Proxy
+ Index idx = DerivedPolicies::convert_index(container.get(), i);
+
+ if (PyObject* shared =
+ ContainerElement::get_links().find(container.get(), idx))
+ {
+ handle<> h(python::borrowed(shared));
+ return object(h);
+ }
+ else
+ {
+ object prox(ContainerElement(container.source(), idx));
+ ContainerElement::
+ get_links().add(prox.ptr(), container.get());
+ return prox;
+ }
+ }
+
+ static void
+ base_replace_indexes(
+ Container& container, Index from,
+ Index to, Index n)
+ {
+ ContainerElement::get_links().replace(container, from, to, n);
+ }
+
+ template <class NoSlice>
+ static void
+ base_erase_index(
+ Container& container, Index i, NoSlice no_slice)
+ {
+ ContainerElement::get_links().erase(container, i, no_slice);
+ }
+
+ static void
+ base_erase_indexes(
+ Container& container, Index from, Index to)
+ {
+ ContainerElement::get_links().erase(container, from, to);
+ }
+ };
+
+ template <
+ class Container
+ , class DerivedPolicies
+ , class ProxyHandler
+ , class Data
+ , class Index
+ >
+ struct slice_helper
+ {
+ static object
+ base_get_slice(Container& container, PySliceObject* slice)
+ {
+ Index from, to;
+ base_get_slice_data(container, slice, from, to);
+ return DerivedPolicies::get_slice(container, from, to);
+ }
+
+ static void
+ base_get_slice_data(
+ Container& container, PySliceObject* slice, Index& from_, Index& to_)
+ {
+ if (Py_None != slice->step) {
+ PyErr_SetString( PyExc_IndexError, "slice step size not supported.");
+ throw_error_already_set();
+ }
+
+ Index min_index = DerivedPolicies::get_min_index(container);
+ Index max_index = DerivedPolicies::get_max_index(container);
+
+ if (Py_None == slice->start) {
+ from_ = min_index;
+ }
+ else {
+ long from = extract<long>( slice->start);
+ if (from < 0) // Negative slice index
+ from += max_index;
+ if (from < 0) // Clip lower bounds to zero
+ from = 0;
+ from_ = boost::numeric_cast<Index>(from);
+ if (from_ > max_index) // Clip upper bounds to max_index.
+ from_ = max_index;
+ }
+
+ if (Py_None == slice->stop) {
+ to_ = max_index;
+ }
+ else {
+ long to = extract<long>( slice->stop);
+ if (to < 0)
+ to += max_index;
+ if (to < 0)
+ to = 0;
+ to_ = boost::numeric_cast<Index>(to);
+ if (to_ > max_index)
+ to_ = max_index;
+ }
+ }
+
+ static void
+ base_set_slice(Container& container, PySliceObject* slice, PyObject* v)
+ {
+ Index from, to;
+ base_get_slice_data(container, slice, from, to);
+
+ extract<Data&> elem(v);
+ // try if elem is an exact Data
+ if (elem.check())
+ {
+ ProxyHandler::base_replace_indexes(container, from, to, 1);
+ DerivedPolicies::set_slice(container, from, to, elem());
+ }
+ else
+ {
+ // try to convert elem to Data
+ extract<Data> elem(v);
+ if (elem.check())
+ {
+ ProxyHandler::base_replace_indexes(container, from, to, 1);
+ DerivedPolicies::set_slice(container, from, to, elem());
+ }
+ else
+ {
+ // Otherwise, it must be a list or some container
+ handle<> l_(python::borrowed(v));
+ object l(l_);
+
+ std::vector<Data> temp;
+ for (int i = 0; i < l.attr("__len__")(); i++)
+ {
+ object elem(l[i]);
+ extract<Data const&> x(elem);
+ // try if elem is an exact Data type
+ if (x.check())
+ {
+ temp.push_back(x());
+ }
+ else
+ {
+ // try to convert elem to Data type
+ extract<Data> x(elem);
+ if (x.check())
+ {
+ temp.push_back(x());
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid sequence element");
+ throw_error_already_set();
+ }
+ }
+ }
+
+ ProxyHandler::base_replace_indexes(container, from, to,
+ temp.end()-temp.begin());
+ DerivedPolicies::set_slice(container, from, to,
+ temp.begin(), temp.end());
+ }
+ }
+ }
+
+ static void
+ base_delete_slice(Container& container, PySliceObject* slice)
+ {
+ Index from, to;
+ base_get_slice_data(container, slice, from, to);
+ ProxyHandler::base_erase_indexes(container, from, to);
+ DerivedPolicies::delete_slice(container, from, to);
+ }
+ };
+
+ template <
+ class Container
+ , class DerivedPolicies
+ , class ProxyHandler
+ , class Data
+ , class Index
+ >
+ struct no_slice_helper
+ {
+ static void
+ slicing_not_suported()
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Slicing not supported");
+ throw_error_already_set();
+ }
+
+ static object
+ base_get_slice(Container& /*container*/, PySliceObject* /*slice*/)
+ {
+ slicing_not_suported();
+ return object();
+ }
+
+ static void
+ base_set_slice(Container& /*container*/, PySliceObject* /*slice*/, PyObject* /*v*/)
+ {
+ slicing_not_suported();
+ }
+
+ static void
+ base_delete_slice(Container& /*container*/, PySliceObject* /*slice*/)
+ {
+ slicing_not_suported();
+ }
+ };
+
+#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
+}} // namespace python::detail
+#endif
+
+ template <class Container, class Index, class Policies>
+ inline typename Policies::data_type*
+ get_pointer(
+ python::detail::container_element<Container, Index, Policies> const& p)
+ {
+ // Get the pointer of a container_element smart pointer
+ return p.get();
+ }
+
+#ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
+ // Don't hide these other get_pointer overloads
+ using boost::python::get_pointer;
+ using boost::get_pointer;
+}} // namespace python::detail
+#endif
+
+} // namespace boost
+
+#endif // INDEXING_SUITE_DETAIL_JDG20036_HPP
diff --git a/boost/python/suite/indexing/indexing_suite.hpp b/boost/python/suite/indexing/indexing_suite.hpp
new file mode 100644
index 0000000000..b636b2111c
--- /dev/null
+++ b/boost/python/suite/indexing/indexing_suite.hpp
@@ -0,0 +1,299 @@
+// (C) Copyright Joel de Guzman 2003.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef INDEXING_SUITE_JDG20036_HPP
+# define INDEXING_SUITE_JDG20036_HPP
+
+# include <boost/python/class.hpp>
+# include <boost/python/def_visitor.hpp>
+# include <boost/python/register_ptr_to_python.hpp>
+# include <boost/python/suite/indexing/detail/indexing_suite_detail.hpp>
+# include <boost/python/return_internal_reference.hpp>
+# include <boost/python/iterator.hpp>
+# include <boost/mpl/or.hpp>
+# include <boost/mpl/not.hpp>
+# include <boost/type_traits/is_same.hpp>
+
+namespace boost { namespace python {
+
+ // indexing_suite class. This class is the facade class for
+ // the management of C++ containers intended to be integrated
+ // to Python. The objective is make a C++ container look and
+ // feel and behave exactly as we'd expect a Python container.
+ // By default indexed elements are returned by proxy. This can be
+ // disabled by supplying *true* in the NoProxy template parameter.
+ //
+ // Derived classes provide the hooks needed by the indexing_suite
+ // to do its job:
+ //
+ // static data_type&
+ // get_item(Container& container, index_type i);
+ //
+ // static object
+ // get_slice(Container& container, index_type from, index_type to);
+ //
+ // static void
+ // set_item(Container& container, index_type i, data_type const& v);
+ //
+ // static void
+ // set_slice(
+ // Container& container, index_type from,
+ // index_type to, data_type const& v
+ // );
+ //
+ // template <class Iter>
+ // static void
+ // set_slice(Container& container, index_type from,
+ // index_type to, Iter first, Iter last
+ // );
+ //
+ // static void
+ // delete_item(Container& container, index_type i);
+ //
+ // static void
+ // delete_slice(Container& container, index_type from, index_type to);
+ //
+ // static size_t
+ // size(Container& container);
+ //
+ // template <class T>
+ // static bool
+ // contains(Container& container, T const& val);
+ //
+ // static index_type
+ // convert_index(Container& container, PyObject* i);
+ //
+ // static index_type
+ // adjust_index(index_type current, index_type from,
+ // index_type to, size_type len
+ // );
+ //
+ // Most of these policies are self explanatory. convert_index and
+ // adjust_index, however, deserves some explanation.
+ //
+ // convert_index converts an Python index into a C++ index that the
+ // container can handle. For instance, negative indexes in Python, by
+ // convention, indexes from the right (e.g. C[-1] indexes the rightmost
+ // element in C). convert_index should handle the necessary conversion
+ // for the C++ container (e.g. convert -1 to C.size()-1). convert_index
+ // should also be able to convert the type of the index (A dynamic Python
+ // type) to the actual type that the C++ container expects.
+ //
+ // When a container expands or contracts, held indexes to its elements
+ // must be adjusted to follow the movement of data. For instance, if
+ // we erase 3 elements, starting from index 0 from a 5 element vector,
+ // what used to be at index 4 will now be at index 1:
+ //
+ // [a][b][c][d][e] ---> [d][e]
+ // ^ ^
+ // 4 1
+ //
+ // adjust_index takes care of the adjustment. Given a current index,
+ // the function should return the adjusted index when data in the
+ // container at index from..to is replaced by *len* elements.
+ //
+
+ template <
+ class Container
+ , class DerivedPolicies
+ , bool NoProxy = false
+ , bool NoSlice = false
+ , class Data = typename Container::value_type
+ , class Index = typename Container::size_type
+ , class Key = typename Container::value_type
+ >
+ class indexing_suite
+ : public def_visitor<
+ indexing_suite<
+ Container
+ , DerivedPolicies
+ , NoProxy
+ , NoSlice
+ , Data
+ , Index
+ , Key
+ > >
+ {
+ private:
+
+ typedef mpl::or_<
+ mpl::bool_<NoProxy>
+ , mpl::not_<is_class<Data> >
+ , typename mpl::or_<
+ is_same<Data, std::string>
+ , is_same<Data, std::complex<float> >
+ , is_same<Data, std::complex<double> >
+ , is_same<Data, std::complex<long double> > >::type>
+ no_proxy;
+
+ typedef detail::container_element<Container, Index, DerivedPolicies>
+ container_element_t;
+
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
+ struct return_policy : return_internal_reference<> {};
+#else
+ typedef return_internal_reference<> return_policy;
+#endif
+
+ typedef typename mpl::if_<
+ no_proxy
+ , iterator<Container>
+ , iterator<Container, return_policy> >::type
+ def_iterator;
+
+ typedef typename mpl::if_<
+ no_proxy
+ , detail::no_proxy_helper<
+ Container
+ , DerivedPolicies
+ , container_element_t
+ , Index>
+ , detail::proxy_helper<
+ Container
+ , DerivedPolicies
+ , container_element_t
+ , Index> >::type
+ proxy_handler;
+
+ typedef typename mpl::if_<
+ mpl::bool_<NoSlice>
+ , detail::no_slice_helper<
+ Container
+ , DerivedPolicies
+ , proxy_handler
+ , Data
+ , Index>
+ , detail::slice_helper<
+ Container
+ , DerivedPolicies
+ , proxy_handler
+ , Data
+ , Index> >::type
+ slice_handler;
+
+ public:
+
+ template <class Class>
+ void visit(Class& cl) const
+ {
+ // Hook into the class_ generic visitation .def function
+ proxy_handler::register_container_element();
+
+ cl
+ .def("__len__", base_size)
+ .def("__setitem__", &base_set_item)
+ .def("__delitem__", &base_delete_item)
+ .def("__getitem__", &base_get_item)
+ .def("__contains__", &base_contains)
+ .def("__iter__", def_iterator())
+ ;
+
+ DerivedPolicies::extension_def(cl);
+ }
+
+ template <class Class>
+ static void
+ extension_def(Class& cl)
+ {
+ // default.
+ // no more extensions
+ }
+
+ private:
+
+ static object
+ base_get_item(back_reference<Container&> container, PyObject* i)
+ {
+ if (PySlice_Check(i))
+ return slice_handler::base_get_slice(
+ container.get(), static_cast<PySliceObject*>(static_cast<void*>(i)));
+
+ return proxy_handler::base_get_item_(container, i);
+ }
+
+ static void
+ base_set_item(Container& container, PyObject* i, PyObject* v)
+ {
+ if (PySlice_Check(i))
+ {
+ slice_handler::base_set_slice(container,
+ static_cast<PySliceObject*>(static_cast<void*>(i)), v);
+ }
+ else
+ {
+ extract<Data&> elem(v);
+ // try if elem is an exact Data
+ if (elem.check())
+ {
+ DerivedPolicies::
+ set_item(container,
+ DerivedPolicies::
+ convert_index(container, i), elem());
+ }
+ else
+ {
+ // try to convert elem to Data
+ extract<Data> elem(v);
+ if (elem.check())
+ {
+ DerivedPolicies::
+ set_item(container,
+ DerivedPolicies::
+ convert_index(container, i), elem());
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "Invalid assignment");
+ throw_error_already_set();
+ }
+ }
+ }
+ }
+
+ static void
+ base_delete_item(Container& container, PyObject* i)
+ {
+ if (PySlice_Check(i))
+ {
+ slice_handler::base_delete_slice(
+ container, static_cast<PySliceObject*>(static_cast<void*>(i)));
+ return;
+ }
+
+ Index index = DerivedPolicies::convert_index(container, i);
+ proxy_handler::base_erase_index(container, index, mpl::bool_<NoSlice>());
+ DerivedPolicies::delete_item(container, index);
+ }
+
+ static size_t
+ base_size(Container& container)
+ {
+ return DerivedPolicies::size(container);
+ }
+
+ static bool
+ base_contains(Container& container, PyObject* key)
+ {
+ extract<Key const&> x(key);
+ // try if key is an exact Key type
+ if (x.check())
+ {
+ return DerivedPolicies::contains(container, x());
+ }
+ else
+ {
+ // try to convert key to Key type
+ extract<Key> x(key);
+ if (x.check())
+ return DerivedPolicies::contains(container, x());
+ else
+ return false;
+ }
+ }
+ };
+
+}} // namespace boost::python
+
+#endif // INDEXING_SUITE_JDG20036_HPP
diff --git a/boost/python/suite/indexing/map_indexing_suite.hpp b/boost/python/suite/indexing/map_indexing_suite.hpp
new file mode 100644
index 0000000000..7fbad4cace
--- /dev/null
+++ b/boost/python/suite/indexing/map_indexing_suite.hpp
@@ -0,0 +1,181 @@
+// (C) Copyright Joel de Guzman 2003.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef MAP_INDEXING_SUITE_JDG20038_HPP
+# define MAP_INDEXING_SUITE_JDG20038_HPP
+
+# include <boost/python/suite/indexing/indexing_suite.hpp>
+# include <boost/python/iterator.hpp>
+# include <boost/python/call_method.hpp>
+# include <boost/python/tuple.hpp>
+
+namespace boost { namespace python {
+
+ // Forward declaration
+ template <class Container, bool NoProxy, class DerivedPolicies>
+ class map_indexing_suite;
+
+ namespace detail
+ {
+ template <class Container, bool NoProxy>
+ class final_map_derived_policies
+ : public map_indexing_suite<Container,
+ NoProxy, final_map_derived_policies<Container, NoProxy> > {};
+ }
+
+ // The map_indexing_suite class is a predefined indexing_suite derived
+ // class for wrapping std::map (and std::map like) classes. It provides
+ // all the policies required by the indexing_suite (see indexing_suite).
+ // Example usage:
+ //
+ // class X {...};
+ //
+ // ...
+ //
+ // class_<std::map<std::string, X> >("XMap")
+ // .def(map_indexing_suite<std::map<std::string, X> >())
+ // ;
+ //
+ // By default indexed elements are returned by proxy. This can be
+ // disabled by supplying *true* in the NoProxy template parameter.
+ //
+ template <
+ class Container,
+ bool NoProxy = false,
+ class DerivedPolicies
+ = detail::final_map_derived_policies<Container, NoProxy> >
+ class map_indexing_suite
+ : public indexing_suite<
+ Container
+ , DerivedPolicies
+ , NoProxy
+ , true
+ , typename Container::value_type::second_type
+ , typename Container::key_type
+ , typename Container::key_type
+ >
+ {
+ public:
+
+ typedef typename Container::value_type value_type;
+ typedef typename Container::value_type::second_type data_type;
+ typedef typename Container::key_type key_type;
+ typedef typename Container::key_type index_type;
+ typedef typename Container::size_type size_type;
+ typedef typename Container::difference_type difference_type;
+
+ template <class Class>
+ static void
+ extension_def(Class& cl)
+ {
+ // Wrap the map's element (value_type)
+ std::string elem_name = "map_indexing_suite_";
+ object class_name(cl.attr("__name__"));
+ extract<std::string> class_name_extractor(class_name);
+ elem_name += class_name_extractor();
+ elem_name += "_entry";
+
+ typedef typename mpl::if_<
+ mpl::and_<is_class<data_type>, mpl::bool_<!NoProxy> >
+ , return_internal_reference<>
+ , default_call_policies
+ >::type get_data_return_policy;
+
+ class_<value_type>(elem_name.c_str())
+ .def("__repr__", &DerivedPolicies::print_elem)
+ .def("data", &DerivedPolicies::get_data, get_data_return_policy())
+ .def("key", &DerivedPolicies::get_key)
+ ;
+ }
+
+ static object
+ print_elem(typename Container::value_type const& e)
+ {
+ return "(%s, %s)" % python::make_tuple(e.first, e.second);
+ }
+
+ static
+ typename mpl::if_<
+ mpl::and_<is_class<data_type>, mpl::bool_<!NoProxy> >
+ , data_type&
+ , data_type
+ >::type
+ get_data(typename Container::value_type& e)
+ {
+ return e.second;
+ }
+
+ static typename Container::key_type
+ get_key(typename Container::value_type& e)
+ {
+ return e.first;
+ }
+
+ static data_type&
+ get_item(Container& container, index_type i_)
+ {
+ typename Container::iterator i = container.find(i_);
+ if (i == container.end())
+ {
+ PyErr_SetString(PyExc_KeyError, "Invalid key");
+ throw_error_already_set();
+ }
+ return i->second;
+ }
+
+ static void
+ set_item(Container& container, index_type i, data_type const& v)
+ {
+ container[i] = v;
+ }
+
+ static void
+ delete_item(Container& container, index_type i)
+ {
+ container.erase(i);
+ }
+
+ static size_t
+ size(Container& container)
+ {
+ return container.size();
+ }
+
+ static bool
+ contains(Container& container, key_type const& key)
+ {
+ return container.find(key) != container.end();
+ }
+
+ static bool
+ compare_index(Container& container, index_type a, index_type b)
+ {
+ return container.key_comp()(a, b);
+ }
+
+ static index_type
+ convert_index(Container& /*container*/, PyObject* i_)
+ {
+ extract<key_type const&> i(i_);
+ if (i.check())
+ {
+ return i();
+ }
+ else
+ {
+ extract<key_type> i(i_);
+ if (i.check())
+ return i();
+ }
+
+ PyErr_SetString(PyExc_TypeError, "Invalid index type");
+ throw_error_already_set();
+ return index_type();
+ }
+ };
+
+}} // namespace boost::python
+
+#endif // MAP_INDEXING_SUITE_JDG20038_HPP
diff --git a/boost/python/suite/indexing/vector_indexing_suite.hpp b/boost/python/suite/indexing/vector_indexing_suite.hpp
new file mode 100644
index 0000000000..34c29ecc6f
--- /dev/null
+++ b/boost/python/suite/indexing/vector_indexing_suite.hpp
@@ -0,0 +1,242 @@
+// (C) Copyright Joel de Guzman 2003.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef VECTOR_INDEXING_SUITE_JDG20036_HPP
+# define VECTOR_INDEXING_SUITE_JDG20036_HPP
+
+# include <boost/python/suite/indexing/indexing_suite.hpp>
+# include <boost/python/suite/indexing/container_utils.hpp>
+# include <boost/python/iterator.hpp>
+
+namespace boost { namespace python {
+
+ // Forward declaration
+ template <class Container, bool NoProxy, class DerivedPolicies>
+ class vector_indexing_suite;
+
+ namespace detail
+ {
+ template <class Container, bool NoProxy>
+ class final_vector_derived_policies
+ : public vector_indexing_suite<Container,
+ NoProxy, final_vector_derived_policies<Container, NoProxy> > {};
+ }
+
+ // The vector_indexing_suite class is a predefined indexing_suite derived
+ // class for wrapping std::vector (and std::vector like) classes. It provides
+ // all the policies required by the indexing_suite (see indexing_suite).
+ // Example usage:
+ //
+ // class X {...};
+ //
+ // ...
+ //
+ // class_<std::vector<X> >("XVec")
+ // .def(vector_indexing_suite<std::vector<X> >())
+ // ;
+ //
+ // By default indexed elements are returned by proxy. This can be
+ // disabled by supplying *true* in the NoProxy template parameter.
+ //
+ template <
+ class Container,
+ bool NoProxy = false,
+ class DerivedPolicies
+ = detail::final_vector_derived_policies<Container, NoProxy> >
+ class vector_indexing_suite
+ : public indexing_suite<Container, DerivedPolicies, NoProxy>
+ {
+ public:
+
+ typedef typename Container::value_type data_type;
+ typedef typename Container::value_type key_type;
+ typedef typename Container::size_type index_type;
+ typedef typename Container::size_type size_type;
+ typedef typename Container::difference_type difference_type;
+
+ template <class Class>
+ static void
+ extension_def(Class& cl)
+ {
+ cl
+ .def("append", &base_append)
+ .def("extend", &base_extend)
+ ;
+ }
+
+ static
+ typename mpl::if_<
+ is_class<data_type>
+ , data_type&
+ , data_type
+ >::type
+ get_item(Container& container, index_type i)
+ {
+ return container[i];
+ }
+
+ static object
+ get_slice(Container& container, index_type from, index_type to)
+ {
+ if (from > to)
+ return object(Container());
+ return object(Container(container.begin()+from, container.begin()+to));
+ }
+
+ static void
+ set_item(Container& container, index_type i, data_type const& v)
+ {
+ container[i] = v;
+ }
+
+ static void
+ set_slice(Container& container, index_type from,
+ index_type to, data_type const& v)
+ {
+ if (from > to) {
+ return;
+ }
+ else {
+ container.erase(container.begin()+from, container.begin()+to);
+ container.insert(container.begin()+from, v);
+ }
+ }
+
+ template <class Iter>
+ static void
+ set_slice(Container& container, index_type from,
+ index_type to, Iter first, Iter last)
+ {
+ if (from > to) {
+ container.insert(container.begin()+from, first, last);
+ }
+ else {
+ container.erase(container.begin()+from, container.begin()+to);
+ container.insert(container.begin()+from, first, last);
+ }
+ }
+
+ static void
+ delete_item(Container& container, index_type i)
+ {
+ container.erase(container.begin()+i);
+ }
+
+ static void
+ delete_slice(Container& container, index_type from, index_type to)
+ {
+ if (from > to) {
+ // A null-op.
+ return;
+ }
+ container.erase(container.begin()+from, container.begin()+to);
+ }
+
+ static size_t
+ size(Container& container)
+ {
+ return container.size();
+ }
+
+ static bool
+ contains(Container& container, key_type const& key)
+ {
+ return std::find(container.begin(), container.end(), key)
+ != container.end();
+ }
+
+ static index_type
+ get_min_index(Container& /*container*/)
+ {
+ return 0;
+ }
+
+ static index_type
+ get_max_index(Container& container)
+ {
+ return container.size();
+ }
+
+ static bool
+ compare_index(Container& /*container*/, index_type a, index_type b)
+ {
+ return a < b;
+ }
+
+ static index_type
+ convert_index(Container& container, PyObject* i_)
+ {
+ extract<long> i(i_);
+ if (i.check())
+ {
+ long index = i();
+ if (index < 0)
+ index += DerivedPolicies::size(container);
+ if (index >= long(container.size()) || index < 0)
+ {
+ PyErr_SetString(PyExc_IndexError, "Index out of range");
+ throw_error_already_set();
+ }
+ return index;
+ }
+
+ PyErr_SetString(PyExc_TypeError, "Invalid index type");
+ throw_error_already_set();
+ return index_type();
+ }
+
+ static void
+ append(Container& container, data_type const& v)
+ {
+ container.push_back(v);
+ }
+
+ template <class Iter>
+ static void
+ extend(Container& container, Iter first, Iter last)
+ {
+ container.insert(container.end(), first, last);
+ }
+
+ private:
+
+ static void
+ base_append(Container& container, object v)
+ {
+ extract<data_type&> elem(v);
+ // try if elem is an exact Data
+ if (elem.check())
+ {
+ DerivedPolicies::append(container, elem());
+ }
+ else
+ {
+ // try to convert elem to data_type
+ extract<data_type> elem(v);
+ if (elem.check())
+ {
+ DerivedPolicies::append(container, elem());
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "Attempting to append an invalid type");
+ throw_error_already_set();
+ }
+ }
+ }
+
+ static void
+ base_extend(Container& container, object v)
+ {
+ std::vector<data_type> temp;
+ container_utils::extend_container(temp, v);
+ DerivedPolicies::extend(container, temp.begin(), temp.end());
+ }
+ };
+
+}} // namespace boost::python
+
+#endif // VECTOR_INDEXING_SUITE_JDG20036_HPP