From 997467c29f1244b3efbc381351d8fa82eae779e8 Mon Sep 17 00:00:00 2001
From: Raoul Gough
- The main iterface to the library is via an object which adds a
- number of Python functions to a class via a single
-
@@ -187,14 +199,14 @@
provides a hook for the
[1] Automatic operation with the standard
- containers works poperly if your compiler supports partial
+ containers works properly if your compiler supports partial
template specializations. Otherwise, refer to the compiler workarounds section.
@@ -239,9 +251,10 @@ namespace boost { namespace python { namespace indexing {
def call. The selection of what Python functions to
- add happens transparently for instances of the standard
- container templates [1], so that code like
- the following should compile and "just work".
+ The main iterface to the library is via the templated class
+ container_suite, an object of which adds a number
+ of Python functions to an extension class via a single
+ def call. Support is provided for all of the
+ standard container templates [1] via
+ container-specific header files, as shown in the following
+ example:
+#include <boost/python/suite/indexing/container_suite.hpp>
+#include <boost/python/suite/indexing/vector.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/module.hpp>
+#include <vector>
+
+BOOST_PYTHON_MODULE(example) {
class_< std::vector<int> > ("vector_int")
.def (indexing::container_suite< std::vector<int> >());
+}
def function to install
multiple Python methods in one call. If the container element
type (int in the example above) is a user-defined
- type, you will have to expose this type to Python via a separate
- class_ instance.
+ type, you would have to expose this type to Python via a
+ separate class_ instance.
indexing::algo_selector
- template, which uses partial template specialization, to
- select what functionality to provide for the container.
+ It does not include any of the container-specific headers
+ (like vector.hpp or set.hpp), so
+ these must be included separately to add support each type
+ of container.
+
+ The container indexing suite includes support for many of the
+ standard C++ container templates, but note that the support code
+ for each is in a separate header file. These header files (in
+ the boost/python/suite/indexing subdirectory) are:
+ vector.hpp, deque.hpp,
+ list.hpp, set.hpp and
+ map.hpp. These correspond in the obvious way to the
+ standard headers vector, deque,
+ etc. The header files for the container_proxy and
+ iterator_range templates provide their own support
+ implicitly.
+
+
boost::shared_ptr or an equivalent. If this
- is not possible, container_proxy may provide a
+ is not possible,
+ container_proxy
+ may provide a
solution, at least for vector-like containers.
@@ -508,14 +540,14 @@ static void visitor_helper (PythonClass &, Policy const &);
In order to include a custom ValueTraits class into
the container suite, it is easiest to supply it as a
specialization of the template
- indexing::value_traits for the container's
- element type. The existing ContainerTraits classes
- all make use of
+ indexing::value_traits for the container's element
+ type. The existing ContainerTraits classes all
+ make use of
value_traits<container::value_type>, and so
will use a specialization for the value type if available. The
default, unspecialized, version of value_traits
- defines equality_comparable as true
- and has an empty implementation of visitor_helper.
+ sets both of the static constants to true and has
+ an empty implementation of visitor_helper.
@@ -770,7 +802,7 @@ namespace boost { namespace python { namespace indexing {
index_style
enum index_style_t
+ index_style_t
#include <map>
#include <string>
-#include <boost/python/suite/indexing/iterator_traits.hpp>
-// Include iterator_traits to get index_style_t
+#include <boost/python/suite/indexing/suite_utils.hpp>
+// Include suite_utils to get index_style_t
struct simple_map_traits {
// Traits information for std::map<std::string, int>
@@ -1160,8 +1192,8 @@ BOOST_PYTHON_MODULE(test_simple) {
-
- The functions should be static, with
container
- & as first parameter.
+ The functions should be static, with
+ container & as first parameter.
@@ -1328,7 +1360,9 @@ namespace boost { namespace python { namespace indexing {
Similar to the above (in fact, it derives from
default_algorithms) except that it uses
container member functions reverse and
- sort instead of the iterator-based versions.
+ sort instead of the iterator-based
+ versions. Defined in
+ boost/python/suite/indexing/list.hpp.
Algorithms::
-make_slice_helper
-(c, s)
+ Algorithms:: make_slice_helper
+ (c, s)
Algorithms::
-slice_helper
+ Algorithms:: slice_helper
c is of type
+ Algorithms:: container & and
+ s is of type indexing::
+ slice const &.
Returns a newly constructed slice_helper
- object by value, where c is of type
- Algorithms::container & and s is
- of type indexing::slice const &.
+ object by value.
slice_helper.
-next()
+ slice_helper.next()
slice_helper.
-current()
+ slice_helper. current()
Algorithms::
-reference
+ Algorithms:: reference
next().
+ slice. This will only be called if the last call to
+ next() returned true.
slice_helper.
-write (v)
+ slice_helper.write (v)
v is of type
+ Algorthims::value_param. Advances to the
+ next element of the slice, as defined in
next, and writes the given value
- v at the new location in the
- container. v will be convertible to
- Algorthims::value_param. If the slice is
- exhausted (i.e. next would return false) then
- write either inserts the value into
- the container at the next location (past the end of the
- slice), or sets a Python exception and throws.
+ v at the new location in the container.If the
+ slice is exhausted (i.e. next would return
+ false) then write either inserts the
+ value into the container at the next location (past the
+ end of the slice), or sets a Python exception and
+ throws.
slice_helper.
-erase_remaining()
+ slice_helper. erase_remaining()
container_proxy template provides an emulation
of Python reference semantics for objects held by value in a
- vector-like container. The primary application of this template
- is in situations where all of the following apply:
+ vector-like container. Of course, this introduces some
+ performance penalties in terms of memory usage and run time, so
+ the primary application of this template is in situations where
+ all of the following apply:
return_internal_reference would be
dangerous.
@@ -1627,20 +1659,32 @@ erase_remaining()
- The container_proxy template wraps a vector-like
- container and presents an interface that is similar to that of a
- normal vector, but which returns element_proxy
- objects instead of plain references to values stored in the
- wrapped container. During an operation that alters the position
- of an element within the container (e.g. insert)
- the container_proxy code updates the relevant proxy
- objects, so that they still refer to the original elements of
- the container. Any operation that would delete or overwrite a
- value in the container (e.g. erase) copies the
- to-be-deleted value into its corresponding proxy object. This
- means that a proxy's "reference" to an element is robust in the
- face of changes to the element's position in the container, and
- even that element's removal.
+ The container_proxy template wraps any vector-like
+ container and presents an interface that is similar to that of
+ std::vector, but which returns
+ element_proxy objects instead of plain references
+ to values stored in the wrapped container. During an operation
+ that alters the position of an element within the container
+ (e.g. insert) the container_proxy code
+ updates the relevant proxy objects, so that they still refer to
+ the same elements at their new locations. Any operation
+ that would delete or overwrite a value in the container
+ (e.g. erase) copies the to-be-deleted value into
+ its corresponding proxy object. This means that a proxy's
+ "reference" to an element is robust in the face of changes to
+ the element's position in the container, and even the element's
+ removal.
+
+
+
+ Ideally, any code that changes the positions of elements within
+ the container would use only the container_proxy
+ interface, to ensure that the proxies are maintained in
+ synchronization. Code that otherwise makes direct modifications
+ to the raw container must notify the
+ container_proxy of the changes, as detailed in the
+ following section.
- The container_proxy interface is designed to be
- convenient to use from C++, and to inter-operate with the
- default_algorithms template. It is important that
- any code that changes element positions within the
- container (at least while proxies for the container exist) uses
- the container_proxy interface, to ensure that the
- proxies get updated. Of course, the interface introduces some
- performance penalties, both in terms of memory usage and run
- time.
+ The container_proxy template takes three
+ parameters, only the first of which is mandatory:
- The Holder template parameter determines how the
- container_proxy stores the raw container object.
- There are currently two types of holder implemented, the default
- identity template which stores it's argument by
- value, and the deref template which stores a
- (plain) pointer to an external object. It would be possible, for
- instance, to create a holder that uses a
- shared_pointer instead.
+
+template<class Container + , class Holder = identity<Container> + , class Generator = vector_generator> class container_proxy; ++
+ The Container argument is the raw container type
+ that the container_proxy will manage. It must
+ provide random-access indexing.
+
+
+
+ The Holder argument determines how the
+ container_proxy stores the raw container object.
+ There are currently two types of holder implemented, the default
+ identity template which will store the raw
+ container by value within the container_proxy, and
+ the deref template which stores a (plain) pointer
+ to an external object. It would also be possible, for instance,
+ to create a holder that uses a shared_pointer, or
+ one that stores a pointer but performs deep copies.
+
+
+
+ The Generator argument determines what container to
+ use for storing the proxy objects. The argument must be a
+ suitable class so that
+ Generator::apply<proxy_t>::type is a typedef
+ for the container to use for storing the proxies. The default is
+ vector_generator, which generates
+ std::vector instances. The usefulness of allowing
+ other generators can be seen from the example
+
+ container_proxy<std::deque<...> >.
+
+ Insertion at the beginning of this container_proxy
+ requires an insertion at the beginning of the
+ std::deque raw container, which has amortized
+ constant time complexity. However, it also requires an insertion
+ at the beginning of the proxy container, which (using the
+ std::vector provided by
+ vector_generator) has linear time complexity. If
+ this is a significant issue, you can use a custom
+ Generator to match the performance characteristics
+ of the proxy container to those of the raw container.
+
+
+ + Examples in libs/python/test/test_container_proxy.cpp + ... + +
namespace boost { namespace python { namespace indexing {
template<class Container
- , class Holder = identity<Container> >
+ , class Holder = identity<Container>
+ , class Generator = vector_generator>
class container_proxy
{
public:
@@ -1690,12 +1776,12 @@ namespace boost { namespace python { namespace indexing {
typedef implementation defined value_type;
typedef implementation defined const_value_type;
+ typedef implementation defined iterator;
+ typedef implementation defined const_iterator;
typedef value_type reference; // Has reference semantics
typedef const_value_type const_reference; // Has reference semantics
- struct iterator { implementation defined }
-
container_proxy ();
explicit container_proxy (held_type const &);
template<typename Iter> container_proxy (Iter, Iter);
@@ -1725,8 +1811,15 @@ namespace boost { namespace python { namespace indexing {
template<typename Iter> void insert (iterator, Iter, Iter);
void push_back (raw_value_type const &);
-
value_type pop_back ();
+
+ // These functions are not normally necessary. They notify the
+ // container_proxy of changes to the raw container made by other
+ // code (see documentation for details)
+ void detach_proxy (size_type index);
+ void detach_proxies (size_type from, size_type to);
+ void prepare_erase (size_type from, size_type to);
+ void notify_insertion (size_type from, size_type to);
};
} } }
@@ -1751,7 +1844,7 @@ namespace boost { namespace python { namespace indexing {
-
+
The deref template.
@@ -1773,6 +1866,21 @@ namespace boost { namespace python { namespace indexing {
+
+ The vector_generator class.
+
+
+namespace boost { namespace python { namespace indexing {
+ struct vector_generator {
+ template<typename Element> struct apply {
+ typedef std::vector<Element> type;
+ };
+ };
+} } }
+
+
+
+
@@ -1783,9 +1891,8 @@ namespace boost { namespace python { namespace indexing {
has a pointer back to the container_proxy object
and an element index within the wrapped container. This can be
seen in the following diagram, which shows a
- containing the three elements 111, 222 and
- 333.
+ container_proxy< vector<int> >
+ containing the three elements 111, 222 and 333.
@@ -1793,17 +1900,17 @@ namespace boost { namespace python { namespace indexing {
+ and an element proxy">
container_proxy with some
- element proxies
+ Diagram 2. Example of container_proxy with an
+ element proxy
element_proxy
object refers (indirectly) to the container element with the
value 222. An insertion before this element would increment the
- element numbers in the shared_proxy objects so that
+ index numbers in the shared_proxy objects so that
the given element_proxy continues to refer to the
same value at its new location. Similary, a deletion before the
element would decrement the affected shared_proxy
- element numbers. If the referenced element itself gets deleted
- or overwritten, the shared_proxy first takes a
+ indexes. If the referenced element itself gets deleted or
+ overwritten, the shared_proxy first takes a
copy of the original value, and is then considered to be
detached from the container_proxy. This
situation is shown below in diagram 3.
@@ -1975,15 +2082,19 @@ namespace boost { namespace python { namespace indexing {
The following Python sequence and mapping functions are not
- currently implemented for any containers: keys, values,
- items, clear, copy, update, pop, __add__, __radd__, __iadd__,
- __mul__, __rmul__ and __imul__. Most of the methods
- mentioned (except for pop) present no particular
- difficulty to implement. The problem with pop is
- that it is incompatible with some return value policies (for
- instance, return_internal_reference) since it must
- return a copy of an element that has already been removed from
- the container. This probably requires an extension to the
+ currently implemented for any containers:
+
+ keys, values, items, clear, copy, update,
+ pop, __add__, __radd__, __iadd__, __mul__, __rmul__
+ and __imul__.
+
+ Most of the methods mentioned (except for pop)
+ present no particular difficulty to implement. The problem with
+ pop is that it is incompatible with some return
+ value policies (for instance,
+ return_internal_reference) since it must return a
+ copy of an element that has already been removed from the
+ container. This probably requires an extension to the
container_suite interface, to allow the client code
the option of specifying a different return policy for this
method in particular.
@@ -2032,18 +2143,19 @@ namespace boost { namespace python { namespace indexing {
Thanks to Joel de Guzman and David Abrahams for input and - encouragement during the development of the container - suite. Joel wrote the original implementation of the indexing - support, which provided many of the ideas embodied in the new - implementation. + encouragement during the development of the container suite, and + to and Ralf W. Grosse-Kunstleve for his invaluable support in + porting to various platforms. Joel wrote the original + implementation of the indexing support, which provided many of + the ideas embodied in the new implementation.
The container suite code and documentation are Copyright (c) - 2003 by Raoul Gough, and licensed under the current Boost - license. + 2003 by Raoul Gough, and licensed according to the Boost license.