From 4c4676db3e3edbccef51c9ec27a23c170e7ce4e2 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Mon, 27 Oct 2003 18:26:46 +0000 Subject: [PATCH] Document SliceHelper and Algorithms override parameter. Rename iterator_pair, fix some mixed case identifiers and include paths. [SVN r20507] --- doc/v2/containers.html | 459 ++++++++++++++++++++++++++++++++--------- 1 file changed, 367 insertions(+), 92 deletions(-) diff --git a/doc/v2/containers.html b/doc/v2/containers.html index 791edc86..f1c3927b 100755 --- a/doc/v2/containers.html +++ b/doc/v2/containers.html @@ -57,9 +57,6 @@
-
- algo_selector -
ValueTraits
@@ -69,6 +66,9 @@
Algorithms
+
+ SliceHelper +
@@ -80,7 +80,7 @@ container_proxy
- iterator_pair + iterator_range
@@ -102,17 +102,23 @@

Introduction

- The purpose of the code described here is to allow Python code to - access C++ containers using the regular Python container + The purpose of the container indexing suite is to allow Python + code to access C++ containers using regular Python interfaces. Since each C++ container is different, it is non-trivial to decide what Python methods can be emulated, and how - to map them to C++ function calls. The library provides a + to map them to C++ function calls. The indexing suite provides a framework for representing those decisions, as well as bindings - for the standard C++ container templates. + for the standard C++ container templates. The indexing headers are + in the Boost subdirectory + boost/python/suite/indexing and non-template + implementations are in + libs/python/src/indexing. Various tests, which can also + serve as examples are in libs/python/test.

Design goals

- The primary design goals are as follows. The library should: + The primary design goals of the container indexing suite are as + follows. The suite should: @@ -177,39 +183,40 @@

The container_suite object achieves this using the - def_visitor interface, which provides a hook for - the 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. + def_visitor interface, which + provides a hook for the 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.

- [1] if your compiler does not support - partial template specializations, you will have to explicitly - select the right algorithms and traits information, as described - in the compiler workarounds section. + [1] Automatic operation with the standard + containers works poperly if your compiler supports partial + template specializations. Otherwise, refer to the compiler workarounds section.

-

container_suite.hpp

+

boost/python/suite/indexing/container_suite.hpp

- The normal interface to the container suite is via the - container_suite.hpp header, which is summarized - below: + The top-level interface to the container suite is via the container_suite.hpp + header which is summarized below:

-

+#include <boost/python/suite/indexing/algo_selector.hpp>
+#include <boost/python/suite/indexing/visitor.hpp>
+
 #include <boost/python/return_by_value.hpp>
 #include <boost/python/return_value_policy.hpp>
-#include "algo_selector.hpp"
-#include "visitor.hpp"
 
 namespace boost { namespace python { namespace indexing {
   typedef return_value_policy<return_by_value> default_container_policies;
@@ -335,19 +342,21 @@ namespace boost { namespace python { namespace indexing {
 
     

- The container_suite template relies on six main - support templates, four of which are suitable for specialization + The container_suite template relies on seven main + support templates, five of which are suitable for specialization or replacement by client code. The following diagram shows the templates [2] and their dependencies, with - the replaceable ones highlighted in grey. + the replaceable ones highlighted in grey. For full details, + refer to the specific section on each component – what + follows here is an overview.

- +
@@ -363,16 +372,48 @@ namespace boost { namespace python { namespace indexing {

- [2] Actually, Algorithms and - ContainerTraits don't represent individual - templates in the diagram, but groups of related - templates. For instance, there are templates called - list_algorithms and assoc_algorithms, - among others. The algo_selector template selects - which algorithms and container traits to use on the basis of - partial template specializations for the known container types. + The visitor template, which implements the def_visitor interface, decides what + Python methods to provide for a container. It takes two template + parameters, Algorithms and Policy (the + CallPolicies for the Python + methods on the container). The Algorithms argument + must provide implementations for the Python methods that the + container supports, as well as a matching + ContainerTraits type. This type provides various + compile-time constants that visitor uses to decide + what Python features the container provides. It also provides a + value_traits typedef, which has similar + compile-time constants related to the values stored in the + container. If the visitor instance decides to + provide Python slice support for the container, it instantiates + the slice_handler template, which also takes + Algorithms and Policy parameters. In + such cases, the Algorithms argument must supply a + SliceHelper type and factory function.

+

+ + The high-level container_suite template uses the + algo_selector template to determine what types to + use in the instantiation of visitor. The + algo_selector template has partial specializations + for all of the STL container templates. + +

+ +

+ + [2] Note that Algorithms and + ContainerTraits don't represent individual + templates in the diagram, but groups of related + templates. For instance, there are actually templates called + list_algorithms and assoc_algorithms, + among others. + +

+

ValueTraits

@@ -512,7 +553,7 @@ namespace boost { namespace python { namespace indexing {

-

value_traits.hpp header

+

Synopsis: boost/python/suite/indexing/value_traits.hpp

@@ -729,7 +770,7 @@ namespace boost { namespace python { namespace indexing {
             index_style
           
           
- Dependencies between main templates - enum IndexStyle + enum index_style_t @@ -1017,7 +1058,7 @@ namespace boost { namespace python { namespace indexing { The following block of code shows a simplistic implementation of ContainerTraits for the container - std::set<std::string, int>. The actual + std::map<std::string, int>. The actual implementation used by the suite relies on template metaprogramming techniques, whereas this example is designed to show only the essential elements of a @@ -1030,7 +1071,7 @@ namespace boost { namespace python { namespace indexing { #include <map> #include <string> #include <boost/python/suite/indexing/iterator_traits.hpp> -// Include iterator_traits to get IndexStyle +// Include iterator_traits to get index_style_t struct simple_map_traits { // Traits information for std::map<std::string, int> @@ -1057,7 +1098,7 @@ struct simple_map_traits { static bool const has_push_back = false; static bool const is_reorderable = false; - static boost::python::indexing::IndexStyle const index_style + static boost::python::indexing::index_style_t const index_style = boost::python::indexing::index_style_nonlinear; struct value_traits_ { @@ -1093,11 +1134,11 @@ struct simple_map_traits { BOOST_PYTHON_MODULE(test_simple) { using namespace boost::python; - typedef std::map<std::string, int> Container; - typedef indexing::map_algorithms<simple_map_traits> Algorithms; + typedef std::map<std::string, int> container_t; + typedef indexing::map_algorithms<simple_map_traits> algorithms_t; - class_<Container> ("map") - .def (indexing::container_suite<Container, Algorithms>()); + class_<container_t> ("map") + .def (indexing::container_suite<container_t, algorithms_t>()); }

@@ -1114,7 +1155,7 @@ BOOST_PYTHON_MODULE(test_simple) { interfaces to the functions can vary to some extent, since the def function calls used internally by the visitor deduce the function type - automatically. However, certain points must be confomed to: + automatically. However, certain points should be confomed to:
  1. @@ -1148,21 +1189,27 @@ BOOST_PYTHON_MODULE(test_simple) { basis for all current implementations of Algorithms. The typedefs that it defines are primarily for convenience within the implementation itself, - however they are also required by the slice_handler - template, if slices are supported. Note that - default_algorithms derives all of the type - information from the container_traits template - argument, which allows the same implementation to be used for - various container types. + however container, reference and + slice_helper are also required by the + slice_handler template, if slices are + supported. Note that default_algorithms derives all + of the type information from its ContainerTraits + template argument, which allows the same implementation to be + used for various container types.

    +

    Partial boost/python/suite/indexing/algorithms.hpp

    +

     namespace boost { namespace python { namespace indexing {
    -  template<typename ContainerTraits>
    -  struct default_algorithms
    +  template<typename ContainerTraits, typename Ovr = detail::no_override>
    +  class default_algorithms
       {
    +    typedef default_algorithms<ContainerTraits, Ovr> self_type;
    +
    +  public:
         typedef ContainerTraits container_traits;
     
         typedef typename ContainerTraits::container   container;
    @@ -1174,6 +1221,8 @@ namespace boost { namespace python { namespace indexing {
         typedef typename ContainerTraits::index_param index_param;
         typedef typename ContainerTraits::key_param   key_param;
     
    +    typedef int_slice_helper<self_type, integer_slice> slice_helper;
    +
         static size_type size       (container &);
         static iterator  find       (container &, key_param);
         static size_type get_index  (container &, key_param);
    @@ -1188,6 +1237,8 @@ namespace boost { namespace python { namespace indexing {
         static void      push_back  (container &, value_param);
         static void      sort       (container &);
     
    +    static slice_helper make_slice_helper (container &c, slice const &);
    +
         template<typename PythonClass, typename Policy>
         static void visitor_helper (PythonClass &, Policy const &);
       };
    @@ -1195,21 +1246,33 @@ namespace boost { namespace python { namespace indexing {
     

    +

    Slice support

    +

    + + For containers that support Python slices, the + visitor template will instantiate and use + internally the slice_handler template. This + template requires a type called slice_helper and a + factory function called make_slice_helper from its + Algorithms argument. More details are provided in + the section SliceHelper. + +

    +

    Usage notes for Algorithms

    - The existing indexing::algo_selector template - uses partial specializations and public derivation to select an + The existing indexing::algo_selector template uses + partial specializations and public derivation to select an Algorithms implementation suitable for any of the standard container types. Exactly how it does this should be considered an implementation detail, and uses some tricks to reuse various existing Algorithms - implementations. In any case, client code can specialize (or - partially specialize) the algo_selector template - for new container types, as long as the specialized instances - conform to the requirements for Algorithms as - already given. + implementations. In any case, client code can specialize the + algo_selector template for new container types, as + long as the specialized instances conform to the requirements + for Algorithms as already given.

    @@ -1317,6 +1380,215 @@ namespace boost { namespace python { namespace indexing {

+ +

+

+ + The default_algorithms template attempts to place + as few restrictions as possible on the container type, by using + iterators and standard algorithms in most of its functions. It + accepts an optional second template parameter, which can be used + via the curiously recurring template idiom to replace any of its + functions that it relies on internally. For instance, if you've + created an iterator-style interface to a container that is not + at all STL-like (let's call it weird_container), + you might be able to re-use most of + default_algorithms by replacing its basic functions + like this: + +

+

+

+namespace indexing = boost::python::indexing;
+
+struct my_algorithms
+  : public indexing::default_algorithms <
+      weird_container_traits, my_algorithms
+  >
+{
+  size_t size (weird_container const &c) {
+    return ...;
+  }
+
+  my_iterator_t begin (weird_container &c) {
+    return ...;
+  }
+
+  my_iterator_t end (weird_container &c) {
+    return ...;
+  }
+};
+
+

+ +

SliceHelper

+ +

+ + Support code for Python slices is split into two portions, the + slice_handler template, and a "slice helper" that + can easily be replaced by client code via a typedef and factory + function in the Algorithms argument supplied to + container_suite. The slice helper object takes care + of reading and writing elements from a slice in a C++ container, + and optionally insertion and deletion. Effectively, the slice + helper object maintains a pointer to the current element of the + slice within the container, and provides a next + function to advance to the next element of the slice. The + container suite uses the following interface for slices: + +

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Expression + + + + Return type + + + + Notes + +
+ + Algorithms:: +make_slice_helper +(c, s) + + + + Algorithms:: +slice_helper + + + + Returns a newly constructed slice_helper + object by value, where c is of type + Algorithms::container & and s is + of type indexing::slice const &. + +
+ + slice_helper. +next() + + + + bool + + + + Advances the slice helper's current element pointer to the + next element of the slice. Returns true if such an element + exists, and false otherwise. The first time this function + is called, it should set the current pointer to the first + element of the slice (if any). + +
+ + slice_helper. +current() + + + + Algorithms:: +reference + + + + Returns a reference to the current element of the + slice. This will only be called after a prior successful + call to next(). + +
+ + slice_helper. +write (v) + + + + void + + + + 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. + +
+ + slice_helper. +erase_remaining() + + + + void + + + + Either erases any remaining elements in the slice + not already consumed by calls to next or + write, + or sets a Python exception and throws. + +
+

+ +

+ + The container suite provides a generic implementation of the + SliceHelper requirements for containers that have + integer-like indexes. It is parameterized with a + SliceType parameter that allows the integer index + values to come from various different sources, the default being + the PySlice_GetIndices function. Refer to the + header file int_slice_helper.hpp + and the references to it in the algorithms.hpp + header for details. +

container_proxy

@@ -1400,6 +1672,9 @@ namespace boost { namespace python { namespace indexing {

+ +

Synopsis: boost/python/suite/indexing/container_proxy.hpp

+
 namespace boost { namespace python { namespace indexing {
   template<class Container
@@ -1570,34 +1845,47 @@ namespace boost { namespace python { namespace indexing {
       
     
 
-    

iterator_pair

+

iterator_range

- The iterator_pair template provides a + The iterator_range template provides a container-like interface to a range defined by two iterators. - The interface is complete enough to allow the container suite to - expose an iterator-defined range as a Python sequence type, with - support for operations that do not require insertion or - deletion. This can be used to expose a C++ array to Python, or - with the result of an equal_range function, or any - other source of two iterators marking out a range of values. See - the getArray function in - libs/python/test/testarray.cpp for an example usage. + The interface is complete enough to provide any Python method + that does not require insertion or deletion, e.g. + len, index and sort. See + the get_array_plain function in libs/python/test/test_array_ext.cpp + for an example usage. If you only need iteration over the values + in a range, consider using the simpler range + function provided by boost/python/iterator.hpp

- iterator_pair should work with any + Beware that C++ iterators are not very Python-like, since they + do not provide any guarantees about the lifetimes of the objects + they refer to. Invalidating either of the iterators stored in an + iterator_range object is dangerous, since + subsequently using the iterators (from Python or C++) results in + undefined behaviour. + +

+

+ + iterator_range should work with any ForwardIterator type.

+

Synopsis: boost/python/suite/indexing/iterator_range.hpp

+

 namespace boost { namespace python { namespace indexing {
   template<typename Iterator>
-  class iterator_pair
+  class iterator_range
   {
   private:
     typedef typename boost::call_traits<Iterator>::param_type iterator_param;
@@ -1611,8 +1899,8 @@ namespace boost { namespace python { namespace indexing {
     typedef typename std_traits::value_type      value_type;
     typedef typename std_traits::pointer         pointer;
 
-    iterator_pair (iterator_param, iterator_param);
-    iterator_pair (std::pair<iterator, iterator> const &);
+    iterator_range (iterator_param, iterator_param);
+    iterator_range (std::pair<iterator, iterator> const &);
 
     iterator begin() const;
     iterator end() const;
@@ -1723,19 +2011,6 @@ namespace boost { namespace python { namespace indexing {
       The sort method (where provided) should allow an
       optional comparison function from Python.
 
-    

-

- - The existing Algorithms should allow a derived - class to replace any of the static member functions without - having to reimplement all of them. For instance, it would be - nice to be able to replace the low-level begin and - end functions in default_algorithms - and have all of the other functions use the replacements - automatically. This would be fairly easy using static - polymorphism, such as the Curiously Recurring Template - Pattern. -

References