[pygccxml-commit] SF.net SVN: pygccxml: [287] pyplusplus_dev/docs
Brought to you by:
mbaas,
roman_yakovenko
From: <rom...@us...> - 2006-07-09 19:09:07
|
Revision: 287 Author: roman_yakovenko Date: 2006-07-09 12:08:54 -0700 (Sun, 09 Jul 2006) ViewCVS: http://svn.sourceforge.net/pygccxml/?rev=287&view=rev Log Message: ----------- adding indexing suite 2 documentatio Added Paths: ----------- pyplusplus_dev/docs/std_containers/ pyplusplus_dev/docs/std_containers/containers.rest pyplusplus_dev/docs/std_containers/indexing_suite_v2.html pyplusplus_dev/docs/std_containers/indexing_suite_v2_files/ pyplusplus_dev/docs/std_containers/indexing_suite_v2_files/boost.css pyplusplus_dev/docs/std_containers/indexing_suite_v2_files/cboost.gif pyplusplus_dev/docs/std_containers/www_configuration.py Added: pyplusplus_dev/docs/std_containers/containers.rest =================================================================== --- pyplusplus_dev/docs/std_containers/containers.rest (rev 0) +++ pyplusplus_dev/docs/std_containers/containers.rest 2006-07-09 19:08:54 UTC (rev 287) @@ -0,0 +1,176 @@ +====================== +C++ containers support +====================== + +.. contents:: Table of contents + +------------ +Introduction +------------ + +C++ has a bunch of containers classes: + + * list + * deque + * queue + * priority_queue + * vector + * stack + * map + * multimap + * hash_map + * hash_multimap + * set + * hash_set + * multiset + * hash_multiset + +It is not a trivial task to expose C++ container to Python. Boost.Python has +a functionality that will help you to expose some of STL containers to `Python`_. +This functionality called - "indexing suite". If you want, you can read more +about indexing suite `here`__. + +.. __ : http://boost.org/libs/python/doc/v2/indexing.html + +Boost.Python, out of the box, supports only ``vector``, ``map`` and ``hash_map`` +containers. In October 2003, Raoul Gough implemented support for the rest of +containers. Well, actually he did much more - he implemented new framework. +This framework provides support for almost all C++ containers and also an easy +way to add support for custom ones. You'd better read his `post`_ to +`boost.python`_ mailing list or `documentation`_ for the new indexing suite. + + +If this suite is soo good, why it is not in the main branch? You can find the +answer here(http://mail.python.org/pipermail/c++-sig/2006-June/010830.html) and +here(http://mail.python.org/pipermail/c++-sig/2006-June/010835.html). + +.. _`documentation` : ./indexing_suite_v2.html +.. _`post` : http://mail.python.org/pipermail/c++-sig/2003-October/005802.html + +------------------------------ +pyplusplus and indexing suites +------------------------------ +`pyplusplus`_ implements support for both indexing suites. More over, you can +freely mix indexing suites. For example you can expose ``std::vector<int>`` using +`boost.python`_ built-in indexing suite and ``std::map< int, std::string>`` using +Raoul Gough's indexing suite. + +----------------- +How does it work? +----------------- + +In both cases, `pyplusplus`_ provides almost "hands free" solution. `pyplusplus`_ +keeps track of all exported functions and variables, and if it sees that there is +a usage of stl container, it exports the container. In both cases, `pyplusplus`_ +analizes the container ``value_type`` ( or in case of mapping containers +``mapped_type`` ), in order to set reasonable defaults, when it generates the code. + +----------------------- +Code, show me the code! +----------------------- + +By default, `pyplusplus`_ works with built-in indexing suite. If you want to use +next version of indexing suite, you should tell this to ``module_builder_t.__init__`` +method: +:: + + mb = module_builder_t( ..., indexing_suite_version=2 ) + +Every declarated class has ``indexing_suite`` property. If the class is an +instantiation of stl container, this property containes reference to an instance +of ``indexing_suite1_t`` or ``indexing_suite2_t`` class. How does `pyplusplus`_ +know that the class represents stl container instantiation? Well, it uses +``pygccxml.declarations.container_traits`` to find out this. This class, provides +all functionality needed to identify container and to find out its ``value_type`` +( ``mapped_type`` ). May I give you small tip? You can use +``pygccxml.declarations.container_traits`` class in search functionality. + + +Built-in indexing suite +----------------------- +.. + + +Indexing suite v1 +----------------- +In this case, `pyplusplus` + +Generated code +-------------- +All generated code will have next form: +:: + + class_< container, other class parameters >(name) + .def( concrete indexing suite class< container, proxy, derived policies >() ) + ; + +Usage example +------------- +C++ code: +:: + + #include <map> + #include <vector> + +:: + + std::vector<string> get_options(){...} + +:: + + struct my_data{...}; + std::map< int, my_data > get_data(); + +Assumption: user wants to use ``get_options`` and ``get_data`` functions. Next +steps will describe what `pyplusplus`_ will do in this case: + +1. `pyplusplus`_ will analyze functions return type and arguments. + +2. It will understand that ``std::vector< std::string >`` and ``std::map< int, my_data >`` + classes should be exported too. + +3. It will understand that those classes should be exported using indexing suite + functionality provided by `boost.python`_ library or `pyplusplus`_ + ``code repository``. + +4. It will generate the code, that will use that functionality. + +So far, so good. Sometimes, there are use cases, when user has to change default +values, for example ``NoProxy`` or ``DerivedPolicies``. What interface `pyplusplus`_ +will provide in order to change the defaults? Well, ``std::vector< std::string >`` +is the class that could be found in declarations tree, right? User can find the +class and change the defaults: +:: + + mb = module_builder_t( ... ) + #the next line will not work, because the real name of std::vector< std::string > + #is platform dependent and much longer. It is there for simplicity. + vector_of_strings = mb.class_( "std::vector< std::string >" ) + vector_of_strings.alias = "StringVector" + vector_of_strings.held_type = ... + vector_of_strings.indexing_suite.no_proxy = False + + +Please, pay attention to the next line: +:: + + vector_of_strings.indexing_suite.no_proxy = False + +Every class, that represents instantiation of some std container will have +class variable ``indexing_suite``, that will be intitialized with relevant +indexing suite class. + + + +.. _`pyplusplus` : ./../pyplusplus.html +.. _`boost.python`: http://www.boost.org/libs/python/doc/index.html +.. _`Python`: http://www.python.org +.. _`GCC-XML`: http://www.gccxml.org + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + End: Added: pyplusplus_dev/docs/std_containers/indexing_suite_v2.html =================================================================== --- pyplusplus_dev/docs/std_containers/indexing_suite_v2.html (rev 0) +++ pyplusplus_dev/docs/std_containers/indexing_suite_v2.html 2006-07-09 19:08:54 UTC (rev 287) @@ -0,0 +1,2213 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html><head> + + + <meta name="generator" content="A human being"> + <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="indexing_suite_v2_files/boost.css"><title>Boost.Python - C++ Container Support</title></head><body> + <table summary="header" border="0" cellpadding="7" cellspacing="0" width="100%"> + <tbody><tr> + <td valign="top" width="300"> + <h3> + <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/index.htm"><img alt="C++ Boost" src="indexing_suite_v2_files/cboost.gif" border="0" height="86" width="277"></a> + </h3> + </td> + <td valign="top"> + <h1 align="center"> + <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/libs/python/doc/index.html">Boost.Python</a><br> + C++ Container Support + </h1> + </td> + </tr> + </tbody></table> + + <hr> + + <h2> + Contents + </h2> + + <dl class="page-index"> + <dt> + <a href="#introduction">Introduction</a> + </dt> + <dt> + <a href="#design_goals">Design goals</a> + </dt> + <dt> + <a href="#interface">Interface</a> + </dt> + <dd> + <dl class="page-index"> + <dt> + <a href="#container_suite">container_suite.hpp</a> + </dt> + <dt> + <a href="#specific">Container-specific headers</a> + </dt> + <dt> + <a href="#policies">Using policies</a> + </dt> + <dt> + <a href="#visitor_flags">Visitor flag values</a> + </dt> + <dt> + <a href="#extending">Extending and customizing</a> + </dt> + <dd> + <dl class="page-index"> + <dt> + <a href="#ValueTraits">ValueTraits</a> + </dt> + <dt> + <a href="#ContainerTraits">ContainerTraits</a> + </dt> + <dt> + <a href="#Algorithms">Algorithms</a> + </dt> + <dt> + <a href="#SliceHelper">SliceHelper</a> + </dt> + </dl> + </dd> + <dt> + <a href="#extending">Container adapters</a> + </dt> + <dd> + <dl class="page-index"> + <dt> + <a href="#container_proxy">container_proxy</a> + </dt> + <dt> + <a href="#iterator_range">iterator_range</a> + </dt> + </dl> + </dd> + <dt> + <a href="#workarounds">Compiler workarounds</a> + </dt> + <dt> + <a href="#limitations">Known limitations</a> + </dt> + </dl> + </dd> + <dt> + <a href="#references">References</a> + </dt> + <dt> + <a href="#acknoweldegments">Acknowledgements and Copyright</a> + </dt> + </dl> + + <h2><a name="introduction">Introduction</a></h2> + + 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 indexing suite provides a + framework for representing those decisions, as well as bindings + for the standard C++ container templates. The indexing headers are + in the Boost subdirectory + <i>boost/python/suite/indexing</i> and non-template + implementations are in + <i>libs/python/src/indexing</i>. Various tests, which can also + serve as examples are in <i>libs/python/test</i>. + + <h2><a name="design_goals">Design goals</a></h2> + + The primary design goals of the container indexing suite are as + follows. The suite should: + + <ul> + <li> + + Support instances of all useful standard container templates + + </li> + <li> + + Provide as much of the normal Python interface as is + reasonable for each container + + </li> + <li> + + Be extensible to user-defined container types + + </li> + <li> + + Support client-provided <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/libs/python/doc/v2/CallPolicies.html">CallPolicies</a> + + </li> + </ul> + + Secondary design goals are as follows. The library should: + + <ul> + <li> + + Provide an emulation of Python reference semantics for + <i>values</i> in vector-like containers. + + </li> + <li> + + Provide an emulation of container semantics for iterator + ranges. + + </li> + </ul> + + <h2><a name="interface">Interface</a></h2> + + <p> + + The main iterface to the library is via the templated class + <code>container_suite</code>, an object of which adds a number + of Python functions to an extension class via a single + <code>def</code> call. Support is provided for all of the + standard container templates <a href="#Note1">[1]</a> via + container-specific header files, as shown in the following + example: + + </p> + +<pre>#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> >()); +} +</pre> + + <p> + + The <code>container_suite</code> object achieves this using the + <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/libs/python/doc/v2/def_visitor.html">def_visitor interface</a>, which + provides a hook for the <code>def</code> function to install + multiple Python methods in one call. If the container element + type (<code>int</code> in the example above) is a user-defined + type, you would have to expose this type to Python via a + separate <code>class_</code> instance. + + </p> + <p> + + <a name="Note1">[1]</a> Automatic operation with the standard + containers works properly if your compiler supports partial + template specializations. Otherwise, refer to the <a href="#workarounds">compiler workarounds</a> section. + + </p> + + <h2><a name="container_suite">boost/python/suite/indexing/container_suite.hpp</a></h2> + + <p> + + The <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/boost/python/suite/indexing/container_suite.hpp"><code>container_suite.hpp</code></a> + header is summarized below: + + </p> + <p> +</p><pre>#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> + +namespace boost { namespace python { namespace indexing { + typedef return_value_policy<return_by_value> default_container_policies; + + template<class Container, + int Flags = 0, + class Algorithms = algo_selector<Container> > + struct container_suite + : public visitor<Algorithms, default_container_policies, Flags> + { + typedef Algorithms algorithms; + + template<typename Policy> + static visitor<Algorithms, Policy, Flags> + with_policies (Policy const &policy) + { + return visitor <Algorithms, Policy> (policy); + } + }; +} } } +</pre> + <p></p> + + <p> + + Some important points to note about <code>container_suite</code>: + + </p><ol> + <li> + + It does not include any of the container-specific headers + (like <code>vector.hpp</code> or <code>set.hpp</code>), so + these must be included separately to add support each type + of container. + + </li> + <li> + + It derives from the <code>indexing::visitor</code> + template, using a <code>return_by_value</code> return + policy. This is a reasonable default, and follows the + Boost.Python idiom of passing a default-constructed object + to the <code>def</code> function. + + </li> + <li> + + The <code>with_policies</code> static function template + generates different instances of the + <code>indexing::visitor</code> template, with + client-provided policies. + + </li> + <li> + + The template parameter <code>Flags</code> allows client code + to disable unneeded features in order to reduce code + size. Details are provided <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/libs/python/doc/v2/visitor_flags">below</a>. + + </li> + </ol> + + <p></p> + + <h2><a name="specific">Container-specific headers</a></h2> + + <p> + + 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 <i>boost/python/suite/indexing</i> subdirectory) are: + <code>vector.hpp</code>, <code>deque.hpp</code>, + <code>list.hpp</code>, <code>set.hpp</code> and + <code>map.hpp</code>. These correspond in the obvious way to the + standard headers <code>vector</code>, <code>deque</code>, + etc. The header files for the <a href="#container_proxy"><code>container_proxy</code></a> and <a href="#iterator_range"><code>iterator_range</code></a> templates + provide their own support implicitly. + + </p> + + <h2><a name="policies">Using policies</a></h2> + + You can select call policies using the + <code>container_suite</code> static member function + <code>with_policies</code> as in the following example: + +<pre> class_< std::list<heavy_class> > ("list_heavy_class") + .def (indexing::container_suite< std::list<heavy_class> > + ::with_policies (my_policies)); +</pre> + + <h3>Caution with policies</h3> + + <p> + + It can be tempting to use <code>return_internal_reference</code> + if the container elements are expensive to copy. However, this + can be quite dangerous, since references to the elements can + easily become invalid (e.g. if the element is deleted or + moved). The Boost.Python code for + <code>return_internal_reference</code> can only manage the + lifetime of the entire container object, and not those of the + elements actually being referenced. Various alternatives exist, + the best of which is to store the container elements indirectly, + using <code>boost::shared_ptr</code> or an equivalent. If this + is not possible, + <code><a href="#container_proxy">container_proxy</a></code> + may provide a + solution, at least for vector-like containers. + + </p> + + <h3>Internal policies detail</h3> + + <p> + + The <code>container_suite</code> object typically adds more than + one function to the Python class, and not all of those functions + can, or should, use exactly the same policies. For instance, the + Python <code>len</code> method, if provided, should always + return its result by value. The library actually uses up to + three different sets of policies derived from the one provided + to the <code>with_policies</code> function. These are: + + </p><ol> + <li> + + The supplied policies, unchanged + + </li> + <li> + + The supplied precall policy only, using <code>default_call_policies</code> for result conversion. + + </li> + <li> + + The supplied precall policies, and the supplied result + conversion policies applied to <i>each element</i> of a + returned list. + + </li> + </ol> + + Roughly speaking, methods returning a single container element + use the first option, while methods returning an integer value + (or <code>void</code>) use the second option. The third option + applies only to the slice version of <code>__getitem__</code>, + which generates a Python list by applying the return conversion + policies to each element in the list. + + <p></p> + + <h2><a name="visitor_flags">Visitor Flag values</a></h2> + + <p> + + The <code>container_suite</code> template has an optional + <code>Flags</code> parameter that allows client code to disable + various optional features of the suite. This can lead to + significant savings in the size of object files and executables + if features such as sorting or Python slice support are not + needed. The <code>Flags</code> parameter (an integer) can be any + bitwise combination of the following values (defined in the + <code>boost::python::indexing</code> namespace by <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/boost/python/suite/indexing/visitor.hpp"><code>visitor.hpp</code></a>): + + </p> + + <p> + + <table border="1"> + <tbody><tr> + <th>Flag</th> + <th>Effect</th> + </tr> + <tr> + + <td><code>disable_len</code></td> + + <td>omits the Python <code>__len__</code> method</td> + + </tr> + <tr> + + <td><code>disable_slices</code></td> + + <td>omits slice support code from <code>__getitem__</code>, + <code>__setitem__</code> and <code>__delitem__</code>.</td> + + </tr> + <tr> + + <td><code>disable_search</code></td> + + <td>omits the container search methods <code>count<code>, + </code>index</code> and <code>__contains__</code></td> + + </tr> + <tr> + + <td><code>disable_reorder</code></td> + + <td>omits the container reordering operations + <code>sort</code> and <code>reverse</code></td> + + </tr> + <tr> + + <td><code>disable_extend</code></td> + + <td>omits the <code>extend</code> method</td> + + </tr> + <tr> + + <td><code>disable_insert</code></td> + + <td>omits the <code>insert</code> method</td> + + </tr> + </tbody></table> + + </p> + + <p> + + Note that some containers don't support some of the optional + features at all, in which case the relevant flags are + ignored. The value <code>minimum_support</code> may be passed as + a flag value to disable all optional features. A simple example + is provided in <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/libs/python/test/test_vector_disable.cpp"><code>test_vector_disable.cpp</code></a> + + </p> + + <h2><a name="extending">Extending and customizing</a></h2> + + <p> + + The <code>container_suite</code> 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 <a href="#Note2">[2]</a> and their dependencies, with + the replaceable ones highlighted in grey. For full details, + refer to the specific section on each component – what + follows here is an overview. + + </p> + + <table align="right"> + <tbody><tr> + <td> + + <img src="indexing_suite_v2_files/overview.png" alt="Dependencies between main templates" height="261" width="486"> + + </td> + </tr> + <tr> + <td><font size="-1"> + + Diagram 1. Overview of class dependencies + + </font></td> + </tr> + </tbody></table> + + <p> + + The <code>visitor</code> template, which implements the <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/libs/python/doc/v2/def_visitor.html">def_visitor interface</a>, decides what + Python methods to provide for a container. It takes two template + parameters, <code>Algorithms</code> and <code>Policy</code> (the + <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/libs/python/doc/v2/CallPolicies.html">CallPolicies</a> for the Python + methods on the container). The <code>Algorithms</code> argument + must provide implementations for the Python methods that the + container supports, as well as a matching + <code>ContainerTraits</code> type. This type provides various + compile-time constants that <code>visitor</code> uses to decide + what Python features the container provides. It also provides a + <code>value_traits</code> typedef, which has similar + compile-time constants related to the values stored in the + container. If the <code>visitor</code> instance decides to + provide Python slice support for the container, it instantiates + the <code>slice_handler</code> template, which also takes + <code>Algorithms</code> and <code>Policy</code> parameters. In + such cases, the <code>Algorithms</code> argument must supply a + <code>SliceHelper</code> type and factory function. + + </p> + <p> + + The high-level <code>container_suite</code> template uses the + <code>algo_selector</code> template to determine what types to + use in the instantiation of <code>visitor</code>. The + <code>algo_selector</code> template has partial specializations + for all of the STL container templates. + + </p> + + <p> + + <a name="Note2">[2]</a> Note that <code>Algorithms</code> and + <code>ContainerTraits</code> don't represent individual + templates in the diagram, but <i>groups</i> of related + templates. For instance, there are actually templates called + <code>list_algorithms</code> and <code>assoc_algorithms</code>, + among others. + + </p> + + + <h2><a name="ValueTraits">ValueTraits</a></h2> + + <p> + + A <code>ValueTraits</code> class provides simple information + about the type of value stored within a container that will be + exposed to Python via the <code>container_suite</code> + interface. It controls the provision of some operations that are + dependant on the operations supported by container elements (for + instance, <code>find</code> requires a comparison operator for + the elements). A <code>ValueTraits</code> class also provides a + hook called during initialization of the Python class, which can + be used for custom processing at this point. + + </p> + <p> + + The following table lists the static constants required in a + <code>ValueTraits</code> class: + + </p> + + <p> + <table border="1"> + <tbody><tr> + <th align="left"> + Static constant + </th> + <th align="center"> + Type + </th> + <th align="left"> + Meaning + </th> + </tr> + + <tr> + <td> + <code>equality_comparable</code> + </td> + <td> + bool + </td> + <td> + + Whether the value supports comparison via + <code>operator==</code>. + + </td> + </tr> + + <tr> + <td> + <code>lessthan_comparable</code> + </td> + <td> + bool + </td> + <td> + + Whether the value supports comparison via + <code>operator<</code>. + + </td> + </tr> + + </tbody></table> + </p> + + <p> + + A <code>ValueTraits</code> class should provide the following + member function template, which will be called during execution + of the <code>def</code> call for the container suite: + + </p> + + <p> + +</p><pre>template <typename PythonClass, typename Policy> +static void visitor_helper (PythonClass &, Policy const &); +</pre> + + <p></p> + + <h3>Usage notes for ValueTraits</h3> + + <p> + + In order to include a custom <code>ValueTraits</code> class into + the container suite, it is easiest to supply it as a + specialization of the template + <code>indexing::value_traits</code> for the container's element + type. The existing <code>ContainerTraits</code> classes all + make use of + <code>value_traits<container::value_type></code>, and so + will use a specialization for the value type if available. The + default, unspecialized, version of <code>value_traits</code> + sets both of the static constants to <code>true</code> and has + an empty implementation of <code>visitor_helper</code>. + + </p> + <p> + + As an example, if a user defined type does not have any + comparison operations, then there will probably be compile-time + errors caused by an attempt to provide the Python + <code>find</code> or <code>sort</code> methods. The solution is + to write a specialized version of + <code>indexing::value_traits</code> that disables the + appropriate features. For example: + + </p> + + <p> +</p><pre>namespace boost { namespace python { namespace indexing { + template<> + struct value_traits<my_type> : public value_traits<int> + { + static bool const equality_comparable = false; + static bool const lessthan_comparable = false; + }; +} } } +</pre> + <p></p> + + <p> + + In this example, there is no need to perform any processing in + the <code>visitor_helper</code> function, and deriving from an + unspecialized version of the template (e.g. + <code>value_traits<int></code>) exposes an empty + <code>visitor_helper</code>. + + </p> + + <h3>Synopsis: boost/python/suite/indexing/value_traits.hpp</h3> + + <p> +</p><pre>namespace boost { namespace python { namespace indexing { + template<typename T> + struct value_traits { + static bool const equality_comparable = true; + static bool const lessthan_comparable = true; + + template<typename PythonClass, typename Policy> + static void visitor_helper (PythonClass &, Policy const &) + { } + }; +} } } +</pre> + <p></p> + + <h2><a name="ContainerTraits">ContainerTraits</a></h2> + + <p> + + A <code>ContainerTraits</code> class serves three + purposes. Firstly, it identifies what facilities the container + supports in principle (i.e. either directly or via some support + code). Secondly, it identifies the types used to pass values + into and out of the supported operations. Thirdly, it provides a + hook for additional code to run during initialization of the + Python class (i.e. during the <code>def</code> call for the + suite). + + </p> + <p> + + Note that a <code>ContainerTraits</code> class can be any class, + derived from the existing implementations or not, as long as it + meets the requirements listed in the following sections. + + </p> + + <h3>Static constants for ContainerTraits</h3> + + The following table lists the static constants that a + <code>ContainerTraits</code> class should define. Note that these + must be <i>compile-time constants</i>, since parts of the library + use these constants to select between template specializations. + The constants must at least be convertible to the type shown in + the second column. + + <p> + <table border="1"> + <tbody><tr> + <th align="left"> + Static constant + </th> + <th align="center"> + Type + </th> + <th align="left"> + Meaning + </th> + <th align="left"> + Influence + </th> + </tr> + <tr> + <td> + <code>has_copyable_iter</code> + </td> + <td align="center"> + <code>bool</code> + </td> + <td> + + Whether copies of an iterator are independant <a href="#Note3">[3]</a> + + </td> + <td> + + Required for <code>len</code> and <code>__iter__</code> + + </td> + </tr> + + <tr> + <td> + <code>is_reorderable</code> + </td> + <td align="center"> + <code>bool</code> + </td> + <td> + + Whether it is possible to re-order the contents of the + container. + + </td> + <td> + + Required for <code>reverse</code> and <code>sort</code> + + </td> + </tr> + + <tr> + <td> + <code>has_mutable_ref</code> + </td> + <td align="center"> + <code>bool</code> + </td> + <td> + Whether container elements can be altered via a reference + </td> + <td> + Determines <code>is_reorderable</code> for most containers. + </td> + </tr> + + <tr> + <td> + <code>has_find</code> + </td> + <td align="center"> + <code>bool</code> + </td> + <td> + + Whether find is possible in principle (via member function + or otherwise) + + </td> + <td> + <code>__contains__</code>, + <code>index</code>, + <code>count</code>, + <code>has_key</code> + </td> + </tr> + + <tr> + <td> + <code>has_insert</code> + </td> + <td align="center"> + <code>bool</code> + </td> + <td> + + Whether it is possible to insert new elements into the container. + + </td> + <td> + <code>insert</code>, + <code>extend</code>, + slice version of <code>__setitem__</code> + </td> + </tr> + + <tr> + <td> + <code>has_erase</code> + </td> + <td align="center"> + <code>bool</code> + </td> + <td> + + Whether it is possible to erase elements from the container. + + </td> + <td> + <code>__delitem__</code>, + slice version of <code>__setitem__</code> + </td> + </tr> + + <tr> + <td> + <code>has_push_back</code> + </td> + <td align="center"> + <code>bool</code> + </td> + <td> + + Whether container supports insertion at the end. + + </td> + <td> + <code>append</code> + </td> + </tr> + + <tr> + <td> + <code>has_pop_back</code> + </td> + <td align="center"> + <code>bool</code> + </td> + <td> + + Whether container supports element deletion at the end. + + </td> + <td> + Currently unused + </td> + </tr> + + <tr> + <td> + <code>index_style</code> + </td> + <td align="center"> + <code>index_style_t</code> + </td> + <td> + + Type of indexing the container supports <a href="#Note4">[4]</a> + + </td> + <td> + <code>__getitem__</code>, + <code>__setitem__</code>, + <code>__delitem__</code>, + <code>__iter__</code>, + <code>extend</code>, + <code>index</code>, + <code>count</code>, + <code>has_key</code> + </td> + </tr> + </tbody></table> + </p> + + <p> + </p><h3>Notes</h3> + + <table> + <tbody><tr> + <td valign="top"> + <a name="Note3">[3]</a> + </td> + <td> + + For example, copies of stream iterators are <i>not</i> + independant. All iterator copies refer to the same stream, + which has only one read and one write position. + + </td> + </tr> + + <tr> + <td valign="top"> + <a name="Note4">[4]</a> + </td> + <td> + + <code>index_style_none</code>, no indexing at all + (e.g. <code>list</code>)<br> + + <code>index_style_linear</code>, continuous integer-like + index type (e.g. <code>vector</code>)<br> + + <code>index_style_nonlinear</code>, indexing via other + types (e.g. <code>map</code>). + + </td> + </tr> + </tbody></table> + + <p></p> + + <h3>Member types for ContainerTraits</h3> + + <p> + + The following table lists the type names that must be defined in + a compatible implementation of <code>ContainerTraits</code>. + The large number of types is supposed to provide flexibility for + containers with differing interfaces. For example, + <code>map</code> uses the same type for searching and "indexing" + (i.e. <code>find</code> and <code>operator[]</code>) so + <code>key_type</code> and <code>index_type</code> would have to + be the same. In contrast, searching a <code>vector</code> would + typically use a different type to that used for indexing into a + vector. + + </p> + + <p> + <table border="1"> + <tbody><tr> + <th align="left"> + Type name + </th> + <th align="left"> + Meaning + </th> + </tr> + + <tr> + <td> + <code>container</code> + </td> + <td> + The type of the C++ container. + </td> + </tr> + + <tr> + <td> + <code>size_type</code> + </td> + <td> + + The type used to represent the number of elements in the + container. + + </td> + </tr> + + <tr> + <td> + <code>iterator</code> + </td> + <td> + + The container's iterator type. This should be a non-const + iterator unless the container itself is const. + + </td> + </tr> + + <tr> + <td> + <code>index_type</code> + </td> + <td> + + The type used to represent indexes extracted from a + <code>__getitem__</code> call (and others). For + <code>index_style_linear</code>, this <i>should be a + signed type</i>, so that negative indices can be + processed. For <code>index_style_nonlinear</code>, this + will most likely be the same type as + <code>key_type</code>. + + </td> + </tr> + + <tr> + <td> + <code>index_param</code> + </td> + <td> + + The type to use when passing <code>index_type</code> into + a function. + + </td> + </tr> + + <tr> + <td> + <code>value_type</code> + </td> + <td> + + The type to use when copying a value into or out of the + container. + + </td> + </tr> + + <tr> + <td> + <code>value_param</code> + </td> + <td> + + The type to use when passing <code>value_type</code> into + a function. + + </td> + </tr> + + <tr> + <td> + <code>key_type</code> + </td> + <td> + + The type used for search operations like <code>find</code> + and <code>count</code>. + + </td> + </tr> + + <tr> + <td> + <code>key_param</code> + </td> + <td> + + The type to use when passing <code>key_type</code> into a + function. + + </td> + </tr> + + <tr> + <td> + <code>reference</code> + </td> + <td> + + The type to use when returning a reference to a container + element. + + </td> + </tr> + + <tr> + <td> + <code>value_traits_</code> + </td> + <td> + + Traits for the container elements. See <a href="#ValueTraits">the ValueTraits section</a> for + information about the requirements on this type. + + </td> + </tr> + + </tbody></table> + + </p> + + <h3>Member functions for ContainerTraits</h3> + + In order to support additional initialization code to run, a + <code>ContainerTraits</code> class should provide a static member + function template as follows: + + <p> +</p><pre>template <typename PythonClass, typename Policy> +static void visitor_helper (PythonClass &, Policy const &); +</pre> + <p></p> + + <p> + + Typically, the implementation would just forward the call to the + equivalent function in the <code>value_traits_</code> class. + + </p> + + <h3>Usage notes for ContainerTraits</h3> + + <p> + + It may be possible to mix your own <code>ContainerTraits</code> + class with one of the existing <code>Algorithms</code> + implementations, thus saving yourself a fair bit of work. The + easiest way to do this would be to specialize the + <code>algo_selector</code> template for your container type, + using public deriviation to get the implementation from one of + the existing <code>Algorithms</code> templates. For example, + assuming that <code>default_algorithms</code> is suitable for + your container: + + </p> + + <p> +</p><pre>namespace boost { namespace python { namespace indexing { + template<> + struct algo_selector<my_container> + : public default_algorithms<my_container_traits> + { + }; +} } } +</pre> + <p></p> + <p> + + Alternatively, you could select the algorithms and traits using + the <code>visitor</code> template directly, as described in the + <a href="#workarounds">compiler workarounds</a> section. + + </p> + + <h3><a name="simple_ctraits">Simplistic ContainerTraits example</a></h3> + + <p> + + The following block of code shows a simplistic implementation of + <code>ContainerTraits</code> for the container + <code>std::map<std::string, int></code>. 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 + <code>ContainerTraits</code> implementation. + + </p> + + <p> +</p><pre>#include <map> +#include <string> +#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> + + typedef std::map<std::string, int> container; + typedef container::size_type size_type; + typedef container::iterator iterator; + + typedef int value_type; + typedef int & reference; + typedef std::string key_type; + typedef std::string index_type; + + typedef int value_param; + typedef std::string const & key_param; + typedef std::string const & index_param; + + static bool const has_copyable_iter = true; + static bool const has_mutable_ref = true; + static bool const has_find = true; + static bool const has_insert = true; + static bool const has_erase = true; + static bool const has_pop_back = false; + static bool const has_push_back = false; + static bool const is_reorderable = false; + + static boost::python::indexing::index_style_t const index_style + = boost::python::indexing::index_style_nonlinear; + + struct value_traits_ { + // Traits information for our value_type + static bool const equality_comparable = true; + static bool const lessthan_comparable = true; + }; + + template<typename PythonClass, typename Policy> + static void visitor_helper (PythonClass &, Policy const &) + { + // Empty + } +}; +</pre> + <p></p> + + <p> + + Example usage of the <code>simple_map_traits</code>: + + </p> + + <p> +</p><pre>#include "simple_map_traits.hpp" + +#include <boost/python/suite/indexing/container_suite.hpp> + +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> + +BOOST_PYTHON_MODULE(test_simple) { + using namespace boost::python; + + typedef std::map<std::string, int> container_t; + typedef indexing::map_algorithms<simple_map_traits> algorithms_t; + + class_<container_t> ("map") + .def (indexing::container_suite<container_t, algorithms_t>()); +} +</pre> + <p></p> + + <h2><a name="Algorithms">Algorithms</a></h2> + + <p> + + The <code>Algorithms</code> requirements are designed to provide + a predictable interface to any container, so that the same + <code>visitor</code> code can expose any supported container to + Python. An implemention of <code>Algorithms</code> does this by + providing functions and typedefs with fixed names. The exact + interfaces to the functions can vary to some extent, since the + <code>def</code> function calls used internally by the + <code>visitor</code> deduce the function type + automatically. However, certain points should be confomed to: + + </p><ol> + <li> + + The functions should be static, with + <code>container &</code> as first parameter. + + </li> + + <li> + + The functions should <i>not</i> be overloaded – this + avoids problems with type deduction. + + </li> + <li> + + Generally, not all of the possible functions need to be + implemented, dependant on the static constants in the + <code>ContainerTraits</code>. + + </li> + </ol> + + <p></p> + + <p> + + The block of code below shows the definition of the + <code>default_algorithms</code> class template, which is the + basis for all current implementations of + <code>Algorithms</code>. The typedefs that it defines are + primarily for convenience within the implementation itself, + however <code>container</code>, <code>reference</code> and + <code>slice_helper</code> are also required by the + <code>slice_handler</code> template, if slices are + supported. Note that <code>default_algorithms</code> derives all + of the type information from its <code>ContainerTraits</code> + template argument, which allows the same implementation to be + used for various container types. + + </p> + + <h3>Partial boost/python/suite/indexing/algorithms.hpp</h3> + + <p> +</p><pre>namespace boost { namespace python { namespace indexing { + 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; + typedef typename ContainerTraits::iterator iterator; + typedef typename ContainerTraits::reference reference; + typedef typename ContainerTraits::size_type size_type; + typedef typename ContainerTraits::value_type value_type; + typedef typename ContainerTraits::value_param value_param; + 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); + static size_type count (container &, key_param); + static bool contains (container &, key_param); + static void reverse (container &); + static reference get (container &, index_param); + static void assign (container &, index_param, value_param); + static void insert (container &, index_param, value_param); + static void erase_one (container &, index_param); + static void erase_range(container &, index_param, index_param); + 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 &); + }; +} } } +</pre> + <p></p> + + <h3>Slice support</h3> + <p> + + For containers that support Python slices, the + <code>visitor</code> template will instantiate and use + internally the <code>slice_handler</code> template. This + template requires a type called <code>slice_helper</code> and a + factory function called <code>make_slice_helper</code> from its + <code>Algorithms</code> argument. More details are provided in + the section <a href="#SliceHelper">SliceHelper</a>. + + </p> + + <h3>Usage notes for Algorithms</h3> + + <p> + + The existing <code>indexing::algo_selector</code> template uses + partial specializations and public derivation to select an + <code>Algorithms</code> 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 <code>Algorithms</code> + implementations. In any case, client code can specialize the + <code>algo_selector</code> template for new container types, as + long as the specialized instances conform to the requirements + for <code>Algorithms</code> as already given. + + </p> + <p> + + A new implementation of <code>Algorithms</code> could derive + from any one of the existing implementation templates, or be + completely independant. The existing implementation templates + are listed in the following table. They each take one template + parameter, which should be a valid <code>ContainerTraits</code> + class, as specified in a <a href="#ContainerTraits">previous + section</a>. + + </p> + + <p> + <table border="1"> + <tbody><tr> + <th> + Template name + </th> + <th> + Description + </th> + </tr> + + <tr> + <td> + + <code>default_algorithms</code> + + </td> + <td> + + Uses standard iterator-based algorithms wherever + possible. Assumes that the container provides + <code>begin</code> and end <code>end</code> member + functions that return iterators, and some or all of + <code>size</code>, <code>insert</code>, <code>erase</code> + and <code>push_back</code>, depending on what functions get + instantiated. + + </td> + </tr> + + <tr> + <td> + + <code>list_algorithms</code> + + </td> + <td> + + Similar to the above (in fact, it derives from + <code>default_algorithms</code>) except that it uses + container member functions <code>reverse</code> and + <code>sort</code> instead of the iterator-based + versions. Defined in + <code>boost/python/suite/indexing/list.hpp</code>. + + </td> + </tr> + + <tr> + <td> + + <code>assoc_algorithms</code> + + </td> + <td> + + Also derived from <code>default_algorithms</code>, for use + with associative containers. Uses the container member + function <code>find</code> for indexing, and member + function <code>count</code> instead of iterator-based + implementations. + + </td> + </tr> + + <tr> + <td> + + <code>set_algorithms</code> + + </td> + <td> + + Derived from <code>assoc_algorithms</code> to handle + <code>set</code> insertion operations, which are slightly + different to the <code>map</code> versions. + + </td> + </tr> + + <tr> + <td> + + <code>map_algorithms</code> + + </td> + <td> + + Derived from <code>assoc_algorithms</code> to handle + <code>map</code> insertion and lookup, which are slightly + different to the <code>set</code> versions. + + </td> + </tr> + </tbody></table> + + </p> + <p> + + The <code>default_algorithms</code> 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 <code>weird_container</code>), + you might be able to re-use most of + <code>default_algorithms</code> by replacing its basic functions + like this: + + </p> + <p> +</p><pre>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 ...; + } +}; +</pre> + <p></p> + + <h2><a name="SliceHelper">SliceHelper</a></h2> + + <p> + + Support code for Python slices is split into two portions, the + <code>slice_handler</code> template, and a "slice helper" that + can easily be replaced by client code via a typedef and factory + function in the <code>Algorithms</code> argument supplied to + <code>container_suite</code>. 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 <code>next</code> + function to advance to the next element of the slice. The + container suite uses the following interface for slices: + + </p> + <p> + <table border="1"> + <tbody><tr> + <th> + + Expression + + </th> + <th> + + Return type + + </th> + <th> + + Notes + + </th> + </tr> + <tr> + <td> + + <code>Algorithms::</code> <code>make_slice_helper</code> + <code>(c, s)</code> + + </td> + <td> + + <code>Algorithms::</code> <code>slice_helper</code> + + </td> + <td> + + <code>c</code> is of type + <code>Algorithms::</code> <code>container &</code> and + <code>s</code> is of type <code>indexing::</code> + <code>slice const &</code>. + Returns a newly constructed <code>slice_helper</code> + object by value. + + </td> + </tr> + + <tr> + <td> + + <code>slice_helper.</code><code>next()</code> + + </td> + <td> + + <code>bool</code> + + </td> + <td> + + 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). + + </td> + </tr> + + <tr> + <td> + + <code>slice_helper.</code> <code>current()</code> + + </td> + <td> + + <code>Algorithms::</code> <code>reference</code> + + </td> + <td> + + Returns a reference to the current element of the + slice. This will only be called if the last call to + <code>next()</code> returned true. + + </td> + </tr> + <tr> + <td> + + <code>slice_helper.</code><code>write (v)</code> + + </td> + <td> + + <code>void</code> + + </td> + <td> + + The parameter <code>v</code> is of type + <code>Algorthims::value_param</code>. Advances to the + next element of the slice, as defined in + <code>next</code>, and writes the given value + <code>v</code> at the new location in the container.If the + slice is exhausted (i.e. <code>next</code> would return + false) then <code>write</code> <i>either</i> inserts the + value into the container at the next location (past the + end of the slice), <i>or</i> sets a Python exception and + throws. + + </td> + </tr> + <tr> + <td> + + <code>slice_helper.</code> <code>erase_remaining()</code> + + </td> + <td> + + <code>void</code> + + </td> + <td> + + <i>Either</i> erases any remaining elements in the slice + not already consumed by calls to <code>next</code> or + <code>write</code>, + <i>or</i> sets a Python exception and throws. + + </td> + </tr> + </tbody></table> + </p> + + <p> + + The container suite provides a generic implementation of the + <code>SliceHelper</code> requirements for containers that have + integer-like indexes. It is parameterized with a + <code>SliceType</code> parameter that allows the integer index + values to come from various different sources, the default being + the <code>PySlice_GetIndices</code> function. Refer to the + header file <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/boost/python/suite/indexing/int_slice_helper.hpp"><code>int_slice_helper.hpp</code></a> + and the references to it in the <a href="http://boost.cvs.sourceforge.net/*checkout*/boost/boost/boost/python/suite/indexing/algorithms.hpp"><code>algorithms.hpp</code></a> + header for details. + + </p> + + <h2><a name="container_proxy">container_proxy</a></h2> + + <p> + + The <code>container_proxy</code> template provides an emulation + of Python reference semantics for objects held by value in a + 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: + + </p><ol> + <li> + + It is not practical to switch to a container of shared + pointers + + </li> + <li> + + Python code requires reference semantics for the objects + within the container + + </li> + <li> + + Element insertion, deletion or assignment takes place, so + that using <code>return_internal_reference</code> would be + dangerous. + + </li> + </ol> + + <p></p> + + <p> + + + The <code>container_proxy</code> template wraps any vector-like + container and presents an interface that is similar to that of + <code>std::vector</code>, but which returns + <code>element_proxy</code> 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. <code>insert</code>) the <code>container_proxy</code> code + updates the relevant proxy objects, so that they still refer to + the <i>same</i> elements at their new locations. Any operation + that would delete or overwrite a value in the container + (e.g. <code>erase</code>) 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 ele... [truncated message content] |