2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-30 20:12:37 +00:00

Synchronize with local work

[SVN r1564]
This commit is contained in:
Raoul Gough
2003-09-18 17:45:39 +00:00
parent 59a243f434
commit 752542b4b3
17 changed files with 1056 additions and 468 deletions

View File

@@ -121,6 +121,24 @@ bool operator< (IntWrapper const &lhs, IntWrapper const &rhs)
return lhs.mI < rhs.mI;
}
int compare (IntWrapper const &lhs, IntWrapper const &rhs)
{
if (lhs < rhs)
{
return -1;
}
else if (rhs < lhs)
{
return 1;
}
else
{
return 0;
}
}
std::ostream &operator<< (std::ostream &strm, IntWrapper const &iw)
{
strm << iw.mI;

View File

@@ -48,6 +48,7 @@ struct IntWrapper {
bool operator== (IntWrapper const &lhs, IntWrapper const &rhs);
bool operator< (IntWrapper const &lhs, IntWrapper const &rhs);
int compare (IntWrapper const &lhs, IntWrapper const &rhs);
std::ostream &operator<< (std::ostream &strm, IntWrapper const &iw);
#endif // IntWrapper_rmg_20030910_included

View File

@@ -33,6 +33,7 @@
// Definitions of supported types
#include "iterator_pair.hpp"
#include "container_proxy.hpp"
#include <set>
#include <map>
#include <list>
@@ -164,6 +165,20 @@ namespace indexing {
typedef default_algorithms<mutable_traits> mutable_algorithms;
typedef default_algorithms<const_traits> const_algorithms;
};
// Container proxies
template <typename RawContainer>
class selector_impl<container_proxy<RawContainer> >
{
typedef container_proxy<RawContainer> Container;
typedef container_proxy_traits<Container> mutable_traits;
typedef container_proxy_traits<Container const> const_traits;
public:
typedef default_algorithms<mutable_traits> mutable_algorithms;
typedef default_algorithms<const_traits> const_algorithms;
};
}
// Select the right algorithms for each supported kind of container

View File

@@ -31,6 +31,7 @@
#include <boost/call_traits.hpp>
#include <algorithm>
#include <stdexcept>
#include <limits>
#include <string>
namespace indexing {
@@ -44,8 +45,8 @@ namespace indexing {
typedef typename ContainerTraits::reference reference;
typedef typename ContainerTraits::key_type key_type;
typedef typename ContainerTraits::size_type size_type;
typedef typename ContainerTraits::index_type index_type;
typedef typename ContainerTraits::value_type value_type;
typedef long index_type; // Ignore container traits (need signed repr.)
typedef typename boost::call_traits<value_type>::param_type value_param;
typedef typename boost::call_traits<key_type>::param_type key_param;
@@ -58,132 +59,26 @@ namespace indexing {
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 (container &, index_param, index_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 void sort (container &, PyObject *);
static iterator begin (container &c) { return c.begin(); }
static iterator end (container &c) { return c.end(); }
template<typename PythonClass, typename Policy>
static void visitor_helper (PythonClass &, Policy const &);
private:
static size_type bounds_check (container &, index_param, char const *msg
, bool one_past = false);
// Throws std::out_of_range if necessary. If one_past is set, then
// indexes up to container.size() *inclusive* are allowed. Otherwise
// returns a normalized index.
};
/////////////////////////////////////////////////////////////////////////
// Get the size of a container
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename default_algorithms<ContainerTraits>::size_type
default_algorithms<ContainerTraits>::size (container &c)
{
return c.size();
}
/////////////////////////////////////////////////////////////////////////
// Find an element in a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename default_algorithms<ContainerTraits>::iterator
default_algorithms<ContainerTraits>::find (container &c
, key_param key)
{
return std::find (begin(c), end(c), key);
}
/////////////////////////////////////////////////////////////////////////
// Count occurances of an element in a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename default_algorithms<ContainerTraits>::size_type
default_algorithms<ContainerTraits>::count (container &c
, key_param key)
{
return std::count (begin(c), end(c), key);
}
/////////////////////////////////////////////////////////////////////////
// Index into a container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename default_algorithms<ContainerTraits>::reference
default_algorithms<ContainerTraits>::get (container &c, index_param ix)
{
return c.at (ix);
}
/////////////////////////////////////////////////////////////////////////
// Assign a value at a particular index (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
default_algorithms<ContainerTraits>::assign (container &c
, index_param ix
, value_param val)
{
c.at(ix) = val;
}
/////////////////////////////////////////////////////////////////////////
// Insert at end of a container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
default_algorithms<ContainerTraits>::push_back (container &c
, value_param v)
{
c.push_back (v);
}
/////////////////////////////////////////////////////////////////////////
// Insert at an index in the container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
default_algorithms<ContainerTraits>::insert (container &c
, index_param i
, value_param v)
{
c.insert (c.begin() + i, v);
}
/////////////////////////////////////////////////////////////////////////
// Erase between given indexes in the container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
default_algorithms<ContainerTraits>::erase (container &c
, index_param from
, index_param to)
{
c.erase (c.begin() + from, c.begin() + to);
}
/////////////////////////////////////////////////////////////////////////
// Reverse the contents of a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void default_algorithms<ContainerTraits>::reverse (container &c)
{
std::reverse (begin(c), end(c));
}
/////////////////////////////////////////////////////////////////////////
// Sort the contents of a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void default_algorithms<ContainerTraits>::sort (container &c)
{
std::sort (begin(c), end(c));
}
/////////////////////////////////////////////////////////////////////////
// Special cases for std::list
/////////////////////////////////////////////////////////////////////////
@@ -203,26 +98,6 @@ namespace indexing {
// static void sort (container &, PyObject *);
};
/////////////////////////////////////////////////////////////////////////
// Reverse the contents of a list (member function version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void list_algorithms<ContainerTraits>::reverse (container &c)
{
c.reverse();
}
/////////////////////////////////////////////////////////////////////////
// Sort the contents of a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void list_algorithms<ContainerTraits>::sort (container &c)
{
c.sort();
}
/////////////////////////////////////////////////////////////////////////
// Special cases for associative containers
/////////////////////////////////////////////////////////////////////////
@@ -239,73 +114,300 @@ namespace indexing {
typedef typename Parent::container container;
typedef typename Parent::reference reference;
typedef typename Parent::key_param key_param;
typedef typename Parent::index_param index_param;
typedef typename Parent::value_param value_param;
// Use the trait's index type information to support non-integer indexes
typedef typename ContainerTraits::index_type index_type;
typedef typename boost::call_traits<index_type>::param_type index_param;
static reference get (container &, index_param);
static void assign (container &, index_param, value_param);
// Use member functions for the following (hiding base class versions)
static void erase_one (container &, key_param);
static iterator find (container &, key_param);
static size_type count (container &, key_param);
};
}
/////////////////////////////////////////////////////////////////////////
// Index into a container (associative version)
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
// Get the size of a container
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename assoc_algorithms<ContainerTraits>::reference
assoc_algorithms<ContainerTraits>::get (container &c, index_param ix)
{
iterator iter = find (c, ix);
template<typename ContainerTraits>
typename indexing::default_algorithms<ContainerTraits>::size_type
indexing::default_algorithms<ContainerTraits>::size (container &c)
{
return c.size();
}
if (iter == end(c))
{
throw std::domain_error
(std::string ("associative container: key not found"));
}
/////////////////////////////////////////////////////////////////////////
// Range check an index and throw out_of_range if necessary
/////////////////////////////////////////////////////////////////////////
else
{
return iter->second;
}
}
template<typename ContainerTraits>
typename indexing::default_algorithms<ContainerTraits>::size_type
indexing::default_algorithms<ContainerTraits>::bounds_check (container &c
, index_param ix
, char const *msg
, bool one_past)
{
size_type bound = size(c) + (one_past ? 1 : 0);
size_type result;
/////////////////////////////////////////////////////////////////////////
// Assign a value at a particular index (associative version)
/////////////////////////////////////////////////////////////////////////
if (ix < 0)
{
if (size_type(-ix) > bound)
{
throw std::out_of_range (msg);
}
template<typename ContainerTraits>
void
assoc_algorithms<ContainerTraits>::assign (container &c
, index_param ix
, value_param val)
{
c[ix] = val;
}
result = bound + ix;
}
/////////////////////////////////////////////////////////////////////////
// Find an element in an associative container
/////////////////////////////////////////////////////////////////////////
else
{
result = ix;
}
template<typename ContainerTraits>
typename assoc_algorithms<ContainerTraits>::iterator
assoc_algorithms<ContainerTraits>::find (container &c, key_param key)
{
return c.find (key);
}
if (result >= bound)
{
throw std::out_of_range (msg);
}
/////////////////////////////////////////////////////////////////////////
// Count occurances of an element in a container (associative version)
/////////////////////////////////////////////////////////////////////////
return result;
}
template<typename ContainerTraits>
typename assoc_algorithms<ContainerTraits>::size_type
assoc_algorithms<ContainerTraits>::count (container &c, key_param key)
{
return c.count (key);
}
/////////////////////////////////////////////////////////////////////////
// Find an element in a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename indexing::default_algorithms<ContainerTraits>::iterator
indexing::default_algorithms<ContainerTraits>::find (container &c
, key_param key)
{
return std::find (begin(c), end(c), key);
}
/////////////////////////////////////////////////////////////////////////
// Count occurances of an element in a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename indexing::default_algorithms<ContainerTraits>::size_type
indexing::default_algorithms<ContainerTraits>::count (container &c
, key_param key)
{
return std::count (begin(c), end(c), key);
}
/////////////////////////////////////////////////////////////////////////
// Index into a container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename indexing::default_algorithms<ContainerTraits>::reference
indexing::default_algorithms<ContainerTraits>::get (container &c
, index_param ix)
{
return c[bounds_check (c, ix, "get")];
}
/////////////////////////////////////////////////////////////////////////
// Assign a value at a particular index (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
indexing::default_algorithms<ContainerTraits>::assign (container &c
, index_param ix
, value_param val)
{
c[bounds_check (c, ix, "assign")] = val;
}
/////////////////////////////////////////////////////////////////////////
// Insert at end of a container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
indexing::default_algorithms<ContainerTraits>::push_back (container &c
, value_param v)
{
c.push_back (v);
}
/////////////////////////////////////////////////////////////////////////
// Insert at an index in the container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
indexing::default_algorithms<ContainerTraits>::insert (container &c
, index_param i
, value_param v)
{
// Index may range up to c.size() inclusive to allow inserting at end
c.insert (c.begin() + bounds_check (c, i, "insert", true), v);
}
/////////////////////////////////////////////////////////////////////////
// Erase between given indexes in the container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
indexing::default_algorithms<ContainerTraits>::erase_range (container &c
, index_param from
, index_param to)
{
// End index is one-past-the-end, so may range up to c.size() inclusive
c.erase (c.begin() + bounds_check (c, from, "erase_range (from)")
, c.begin() + bounds_check (c, to, "erase_range (to)", true));
}
/////////////////////////////////////////////////////////////////////////
// Erase one element at the given index in the container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
indexing::default_algorithms<ContainerTraits>::erase_one (container &c
, index_param ix)
{
c.erase (c.begin() + bounds_check (c, ix, "erase_one"));
}
/////////////////////////////////////////////////////////////////////////
// Reverse the contents of a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void indexing::default_algorithms<ContainerTraits>::reverse (container &c)
{
std::reverse (begin(c), end(c));
}
/////////////////////////////////////////////////////////////////////////
// Sort the contents of a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void indexing::default_algorithms<ContainerTraits>::sort (container &c)
{
std::sort (begin(c), end(c));
}
/////////////////////////////////////////////////////////////////////////
// Visitor helper function (default version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
template<typename PythonClass, typename Policy>
void
indexing::default_algorithms<ContainerTraits>
::visitor_helper (PythonClass &pyClass, Policy const &policy)
{
container_traits::visitor_helper (pyClass, policy);
}
/////////////////////////////////////////////////////////////////////////
// Reverse the contents of a list (member function version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void indexing::list_algorithms<ContainerTraits>::reverse (container &c)
{
c.reverse();
}
/////////////////////////////////////////////////////////////////////////
// Sort the contents of a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void indexing::list_algorithms<ContainerTraits>::sort (container &c)
{
c.sort();
}
/////////////////////////////////////////////////////////////////////////
// Index into a container (associative version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename indexing::assoc_algorithms<ContainerTraits>::reference
indexing::assoc_algorithms<ContainerTraits>::get (container &c, index_param ix)
{
iterator iter = find (c, ix);
if (iter == end(c))
{
// ? Is domain_error appropriate here?
throw std::domain_error
(std::string ("associative container get: key not found"));
}
else
{
return iter->second;
}
}
/////////////////////////////////////////////////////////////////////////
// Erase elements with the given key (associative version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
indexing::assoc_algorithms<ContainerTraits>::erase_one (container &c
, key_param key)
{
if (c.erase (key) == 0)
{
// ? Is domain_error appropriate here?
throw std::domain_error
(std::string ("associative container erase: key not found"));
}
}
/////////////////////////////////////////////////////////////////////////
// Assign a value at a particular index (associative version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
indexing::assoc_algorithms<ContainerTraits>::assign (container &c
, index_param ix
, value_param val)
{
c[ix] = val;
}
/////////////////////////////////////////////////////////////////////////
// Find an element in an associative container
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename indexing::assoc_algorithms<ContainerTraits>::iterator
indexing::assoc_algorithms<ContainerTraits>::find (container &c, key_param key)
{
return c.find (key);
}
/////////////////////////////////////////////////////////////////////////
// Count occurances of an element in a container (associative version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename indexing::assoc_algorithms<ContainerTraits>::size_type
indexing::assoc_algorithms<ContainerTraits>::count (container &c
, key_param key)
{
return c.count (key);
}
#endif // algorithms_rmg_20030823_included

View File

@@ -25,6 +25,7 @@
#define container_proxy_rmg_20030826_included
#include "shared_proxy_impl.hpp"
#include "element_proxy.hpp"
#include <map>
#include <memory>
#include <cassert>
@@ -60,139 +61,20 @@ public:
typedef typename Container::value_type raw_value_type;
struct const_element_proxy;
typedef element_proxy<self_type> value_type;
typedef value_type reference; // Already has ref. semantics
class element_proxy
{
friend class const_element_proxy;
typedef shared_proxy proxy_type;
typedef boost::shared_ptr<proxy_type> proxy_pointer;
proxy_pointer mPtr;
public:
typedef typename proxy_type::value_type value_type;
typedef typename proxy_type::reference reference;
typedef typename proxy_type::pointer pointer;
typedef typename proxy_type::iterator_category iterator_category;
typedef typename proxy_type::difference_type difference_type;
typedef value_type element_type; // Alias for register_ptr_to_python
element_proxy () : mPtr () { }
explicit element_proxy (proxy_type *ptr) : mPtr (ptr) { }
element_proxy (proxy_pointer const &ptr) : mPtr (ptr) { }
explicit element_proxy (raw_value_type const &val)
: mPtr (new proxy_type(val))
{
// Create new standalone value (i.e. detached)
}
reference operator* () const { return mPtr->operator*(); }
pointer operator-> () const { return (*mPtr).operator->(); }
pointer get () const { return operator->(); } // Alias for pointer_holder
// Implicit conversion to raw_value_type
operator reference () const { return operator*(); }
// These are necessary (at least) while the indexing suite insists
// on converting the real container's value_type to the proxy
// container's value_type when going from Python to C++. If the
// suite would just pass the real container's value_type through,
// our implicit conversion to value_type might suffice.
bool operator== (value_type const &other) { return (**this) == other; }
bool operator!= (value_type const &other) { return (**this) != other; }
bool operator< (value_type const &other) { return (**this) < other; }
bool operator> (value_type const &other) { return (**this) > other; }
element_proxy &operator= (value_type const &copy)
{
proxy_type &proxy (*mPtr);
container_proxy *container = proxy.owner();
size_type index = proxy.index();
if (container)
{
container->replace (index, copy);
// Proxy was attached before, but is now detached. Make sure
// we now refer to the new element, instead of the detached
// copy of the old element
mPtr = container->at (index).mPtr;
// Note: in the special case that this we and the container
// proxy itself have the only references to the
// shared_proxy_impl, it is not necessary to first detach
// the proxy. Maybe best to implement when changing to
// intrusive_ptr instead of shared_ptr.
}
else
{
*proxy = copy;
}
return *this;
}
element_proxy &operator= (element_proxy const &copy)
{
// This is the most dubious bit of the fudge. The indexing_suite's
// implementation of __setitem__ tries to pass us our value_type,
// which is actually of type element_proxy
return (*this) = *copy;
}
size_t use_count() const { return mPtr.use_count(); } // For debugging
};
struct const_element_proxy
{
typedef shared_proxy proxy_type;
typedef boost::shared_ptr<proxy_type> proxy_pointer;
proxy_pointer mPtr;
public:
typedef typename proxy_type::value_type const value_type;
typedef value_type &reference;
typedef value_type *pointer;
typedef typename proxy_type::iterator_category iterator_category;
typedef typename proxy_type::difference_type difference_type;
const_element_proxy () : mPtr () { }
explicit const_element_proxy (proxy_type *ptr) : mPtr (ptr) { }
const_element_proxy (proxy_pointer const &ptr) : mPtr (ptr) { }
const_element_proxy (element_proxy const &copy) : mPtr (copy.mPtr) { }
explicit const_element_proxy (raw_value_type const &val)
: mPtr (new proxy_type(val))
{
// Create new standalone value (i.e. detached)
}
reference operator* () const { return mPtr->operator*(); }
pointer operator-> () const { return mPtr->operator->(); }
// Implicit conversion to raw_value_type
operator reference () const { return operator*(); }
size_t use_count() const { return mPtr.use_count(); } // For debugging
};
typedef element_proxy value_type;
typedef element_proxy reference; // Already has reference semantics
typedef const_element_proxy const_value_type;
typedef const_element_proxy<self_type> const_value_type;
typedef const_value_type const_reference; // Has ref. semantics
public:
struct iterator
{
typedef typename raw_iterator_traits::difference_type difference_type;
typedef std::random_access_iterator_tag iterator_category;
typedef element_proxy value_type;
typedef element_proxy *pointer;
typedef element_proxy reference; // Already has reference semantics
typedef container_proxy::value_type value_type;
typedef value_type *pointer;
typedef value_type reference; // Already has reference semantics
iterator (container_proxy *p, size_type i) : ptr (p), index (i) { }
@@ -246,11 +128,11 @@ public:
Container & container(); // Should be private?
Container const &container() const; // Should be private?
element_proxy at (size_type index);
const_element_proxy at (size_type index) const;
reference at (size_type index);
const_reference at (size_type index) const;
element_proxy operator[] (size_type index) { return at(index); }
const_element_proxy operator[] (size_type index) const { return at(index); }
reference operator[] (size_type index) { return at(index); }
const_reference operator[] (size_type index) const { return at(index); }
size_type size() const { return container().size(); }
size_type capacity() const { return container().capacity(); }
@@ -267,8 +149,8 @@ public:
void push_back (raw_value_type const &copy) { insert (end(), copy); }
element_proxy pop_back () {
element_proxy result = at (end() - 1);
value_type pop_back () {
value_type result = at (end() - 1);
erase (end() - 1);
return result;
}
@@ -378,7 +260,7 @@ container_proxy<Container, HeldType, Accessor>
}
template<class Container, typename HeldType, class Accessor>
typename container_proxy<Container, HeldType, Accessor>::element_proxy
typename container_proxy<Container, HeldType, Accessor>::reference
container_proxy<Container, HeldType, Accessor>
::at (size_type index)
{
@@ -389,11 +271,11 @@ container_proxy<Container, HeldType, Accessor>
entry.reset (new shared_proxy (this, index));
}
return element_proxy (entry);
return reference (entry);
}
template<class Container, typename HeldType, class Accessor>
typename container_proxy<Container, HeldType, Accessor>::const_element_proxy
typename container_proxy<Container, HeldType, Accessor>::const_reference
container_proxy<Container, HeldType, Accessor>
::at (size_type index) const
{
@@ -403,7 +285,7 @@ container_proxy<Container, HeldType, Accessor>
container_proxy *mutable_this = const_cast<container_proxy *>(this);
return const_element_proxy (mutable_this->at (index));
return const_reference (mutable_this->at (index));
}
template<class Container, typename HeldType, class Accessor>

View File

@@ -35,12 +35,14 @@ namespace indexing {
template<class Container, class Algorithms = algo_selector<Container> >
struct container_suite
{
typedef Algorithms algorithms;
typedef boost::python::return_value_policy<boost::python::return_by_value>
default_policies;
static visitor<Algorithms, default_policies> generate ()
{
return visitor <Algorithms, default_policies> (default_policies());
return visitor <Algorithms, default_policies> ();
}
template<typename Policy>

View File

@@ -2,6 +2,9 @@
//
// Header file container_traits.hpp
//
// Traits information about entire containers for use in determining
// what Python methods to support for a container.
//
// Copyright (c) 2003 Raoul M. Gough
//
// This material is provided "as is", with absolutely no warranty expressed
@@ -26,75 +29,77 @@
#define container_traits_rmg_20030823_included
#include "suite_utils.hpp"
#include "iterator_suite.hpp"
#include "iterator_traits.hpp"
#include "value_traits.hpp"
#include <boost/type_traits.hpp>
namespace indexing {
/////////////////////////////////////////////////////////////////////////
// Lowest common denominator traits - applicable to real containers
// and iterator pairs
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct base_container_traits
: public iterator_detail::traits_by_category<typename Container::iterator>
::type
{
protected:
typedef typename
iterator_detail::traits_by_category<typename Container::iterator>
::type base_type;
BOOST_STATIC_CONSTANT (bool, is_mutable
= ! boost::is_const<Container>::value);
public:
typedef Container container;
typedef typename container::size_type size_type;
typedef typename container::size_type index_type; // at(), operator[]
typedef typename base_type::value_type key_type; // find, count, ...
// *FIXME* should probably override the typedefs for iterator,
// value_type and reference with the const versions if !is_mutable
typedef value_traits<typename base_type::value_type> value_traits_;
BOOST_STATIC_CONSTANT (bool, has_mutable_ref
= base_type::has_mutable_ref && is_mutable);
BOOST_STATIC_CONSTANT (bool, has_find
= value_traits_::equality_comparable);
// Assume the worst for everything else
BOOST_STATIC_CONSTANT (bool, has_insert = false);
BOOST_STATIC_CONSTANT (bool, has_erase = false);
BOOST_STATIC_CONSTANT (bool, has_pop_back = false);
BOOST_STATIC_CONSTANT (bool, has_push_back = false);
// Forward visitor_helper to value_traits_
template<typename PythonClass, typename Policy>
static void visitor_helper (PythonClass &, Policy const &);
};
/////////////////////////////////////////////////////////////////////////
// Traits for the iterator_pair container emulator
/////////////////////////////////////////////////////////////////////////
template<typename IteratorPair>
struct iterator_pair_traits
: public
iterator_detail::traits_by_category<typename IteratorPair::iterator>::type
struct iterator_pair_traits : public base_container_traits<IteratorPair>
{
typedef IteratorPair container;
typedef typename IteratorPair::size_type size_type;
typedef typename IteratorPair::size_type index_type; // at()
static bool const has_insert = false;
static bool const has_erase = false;
static bool const has_pop_back = false;
static bool const has_push_back = false;
};
/////////////////////////////////////////////////////////////////////////
// Lowest common denominator (almost all "real" containers would
// meet at least these requirements)
// Default container traits - almost all "real" containers would meet
// at least these requirements
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct default_container_traits
struct default_container_traits : public base_container_traits<Container>
{
protected:
static bool const is_mutable = ! boost::is_const<Container>::value;
public:
typedef Container container;
// *FIXME* should use value_type const and const_reference if !is_mutable
typedef typename Container::value_type value_type;
typedef typename Container::reference reference;
typedef typename Container::difference_type difference_type;
typedef typename Container::size_type size_type;
typedef typename Container::size_type index_type; // at()
typedef value_type key_type; // find, count, ...
// Should probably select iterator or const_iterator on the
// basis of is_mutable
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
static bool const has_copyable_iter = true;
static IndexStyle const index_style
= ::indexing::iterator_traits<iterator>::index_style;
static bool const has_mutable_ref
= is_mutable && is_mutable_ref<reference>::value;
// has_mutable_ref basically means that the container supports
// in-place replacement of values (e.g. the associative containers
// *don't*)
static bool const is_reversible = has_mutable_ref;
static bool const has_insert = is_mutable;
static bool const has_erase = is_mutable;
static bool const has_pop_back = false;
static bool const has_push_back = false;
BOOST_STATIC_CONSTANT (bool, has_insert = is_mutable);
BOOST_STATIC_CONSTANT (bool, has_erase = is_mutable);
};
/////////////////////////////////////////////////////////////////////////
@@ -104,8 +109,25 @@ namespace indexing {
template<typename Container>
struct default_sequence_traits : public default_container_traits<Container>
{
static bool const has_pop_back = is_mutable;
static bool const has_push_back = is_mutable;
BOOST_STATIC_CONSTANT (bool, has_pop_back = is_mutable);
BOOST_STATIC_CONSTANT (bool, has_push_back = is_mutable);
};
/////////////////////////////////////////////////////////////////////////
// Sequences within a container_proxy
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct container_proxy_traits : public default_sequence_traits<Container>
{
typedef Container container;
typedef typename container::raw_value_type value_type; // insert, ...
typedef typename container::raw_value_type key_type; // find, count, ...
typedef typename container::reference reference; // return values
typedef value_traits<reference> value_traits_;
// Get value_traits for the reference type (i.e. element_proxy)
// to get the custom visitor_helper
};
/////////////////////////////////////////////////////////////////////////
@@ -115,7 +137,8 @@ namespace indexing {
template<typename Container>
struct set_traits : public default_container_traits<Container>
{
static IndexStyle const index_style = index_style_nonlinear;
BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_nonlinear);
BOOST_STATIC_CONSTANT (bool, has_find = true);
};
/////////////////////////////////////////////////////////////////////////
@@ -131,8 +154,22 @@ namespace indexing {
typedef typename Container::key_type index_type; // at()
typedef typename Container::key_type key_type; // find, count, ...
static IndexStyle const index_style = index_style_nonlinear;
BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_nonlinear);
BOOST_STATIC_CONSTANT (bool, has_find = true);
};
}
/////////////////////////////////////////////////////////////////////////
// Visitor helper function (foward to value_traits_ version)
/////////////////////////////////////////////////////////////////////////
template<typename Container>
template<typename PythonClass, typename Policy>
void
indexing::base_container_traits<Container>
::visitor_helper (PythonClass &pyClass, Policy const &policy)
{
value_traits_::visitor_helper (pyClass, policy);
}
#endif // container_suite_rmg_20030823_included

View File

@@ -21,15 +21,27 @@
// $Id$
//
#ifndef NEWSTYLE
# define NEWSTYLE 1
#endif
#include "container_proxy.hpp"
#include "IntWrapper.hpp"
#if NEWSTYLE
#include "container_suite.hpp"
#endif
#include <boost/python/def.hpp>
#include <boost/python/class.hpp>
#include <boost/python/module.hpp>
#include <boost/python/implicit.hpp>
#if !NEWSTYLE
#include <boost/python/suite/indexing/indexing_suite.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#endif
#include <boost/lexical_cast.hpp>
#include <string>
@@ -57,27 +69,47 @@ void pointer_increment (boost::shared_ptr<IntWrapper> const &ptr)
(*ptr).increment();
}
IntWrapper *get_pointer (container_proxy<std::vector<IntWrapper> >::value_type const &proxy)
{
return &(*proxy);
}
BOOST_PYTHON_MODULE (indexing)
{
boost::python::def ("trace", &IntWrapper::setTrace);
boost::python::def ("setTrace", &IntWrapper::setTrace);
typedef std::vector<IntWrapper> Container;
typedef container_proxy<Container> ProxyContainer;
typedef boost::shared_ptr<IntWrapper> Pointer;
typedef std::vector<Pointer> PointerContainer;
using boost::python::vector_indexing_suite;
boost::python::implicitly_convertible <int, IntWrapper>();
// typedef vector_indexing_suite<Container, true> Suite;
#if NEWSTYLE
typedef boost::python::return_value_policy<boost::python::return_by_value>
default_policies;
// Not really the same thing - returning internal references
typedef indexing::visitor
<indexing::container_suite<Container>::algorithms
, boost::python::return_internal_reference<> > ProxySuite;
typedef indexing::visitor
<indexing::container_suite<ProxyContainer>::algorithms
, default_policies> ProxyContainerSuite;
typedef indexing::visitor
<indexing::container_suite<PointerContainer>::algorithms
, default_policies> PointerContainerSuite;
#else
using boost::python::vector_indexing_suite;
typedef vector_indexing_suite<Container, false> ProxySuite;
typedef vector_indexing_suite<ProxyContainer, true> ProxyContainerSuite;
typedef vector_indexing_suite<PointerContainer, true> PointerContainerSuite;
boost::python::implicitly_convertible <IntWrapper, ProxyContainer::value_type>();
boost::python::register_ptr_to_python<ProxyContainer::value_type>();
#endif
boost::python::class_<Container> ("Vector")
.def (ProxySuite())
.def ("reserve", &Container::reserve);
@@ -90,21 +122,11 @@ BOOST_PYTHON_MODULE (indexing)
.def (PointerContainerSuite())
.def ("reserve", &PointerContainer::reserve);
boost::python::implicitly_convertible <IntWrapper, ProxyContainer::value_type>();
boost::python::class_<IntWrapper> ("IntWrapper", boost::python::init<int>())
.def ("increment", &IntWrapper::increment)
.def ("__repr__", &boost::lexical_cast<std::string, IntWrapper>)
;
// Ultimately, all of the value_type's properties should be provided
// via something like register_ptr_to_python with double-dereferencing.
// boost::python::class_<ProxyContainer::value_type> ("Container__value_type", boost::python::init<IntWrapper>())
// .def ("increment", proxy_increment<ProxyContainer>)
// .def ("__repr__", proxy_repr<ProxyContainer>)
// ;
boost::python::register_ptr_to_python<ProxyContainer::value_type>();
boost::python::implicitly_convertible <IntWrapper, Pointer>();
boost::python::class_<Pointer> ("Pointer", boost::python::no_init)

View File

@@ -37,28 +37,6 @@ void indexing::slice::validate () const
}
}
/////////////////////////////////////////////////////////////////////////////
// Slice constructor
/////////////////////////////////////////////////////////////////////////////
indexing::slice::slice (boost::python::detail::borrowed_reference ref)
: boost::python::object (ref)
, mStart (0)
, mStep (0)
, mStop (0)
, mDirection (0)
{
if (!PySlice_Check (this->ptr()))
{
PyErr_SetString (PyExc_TypeError
, "slice constructor: passed a non-slice object");
boost::python::throw_error_already_set();
}
// This slice object is useless until setLength is called
}
/////////////////////////////////////////////////////////////////////////////
// Set up our member variables for a sequence of a given length
/////////////////////////////////////////////////////////////////////////////

View File

@@ -24,7 +24,6 @@
#ifndef slice_rmg_20030910_included
#define slice_rmg_20030910_included
#include <Python.h>
#include <boost/python/object.hpp>
#include <boost/python/converter/pytype_object_mgr_traits.hpp>
@@ -38,7 +37,8 @@ namespace indexing
// A newly constructed slice object is useless until setLength is called
//
slice (boost::python::detail::borrowed_reference ref);
template<typename T> slice (T const &ref);
void setLength (int sequenceLength);
int start() const { validate(); return mStart; }
@@ -59,6 +59,25 @@ namespace indexing
};
}
template<typename T>
indexing::slice::slice (T const &ref)
: boost::python::object (ref)
, mStart (0)
, mStep (0)
, mStop (0)
, mDirection (0)
{
if (!PySlice_Check (this->ptr()))
{
PyErr_SetString (PyExc_TypeError
, "slice constructor: passed a non-slice object");
boost::python::throw_error_already_set();
}
// This slice object is still useless until setLength is called
}
namespace boost { namespace python { namespace converter {
// Specialized converter to handle PySlice_Type objects
template<>

View File

@@ -40,6 +40,8 @@ namespace indexing
{
static boost::python::object make_getitem (Policy const &);
static boost::python::object make_setitem (Policy const &);
static boost::python::object make_delitem (Policy const &);
static boost::python::object make_extend (Policy const &);
private:
typedef typename Algorithms::container container;
@@ -47,6 +49,8 @@ namespace indexing
static boost::python::list get_slice (container &, slice);
static void set_slice (container &, slice, boost::python::object);
static void del_slice (container &, slice);
static void extend (container &, boost::python::object);
struct postcall_override
{
@@ -111,7 +115,7 @@ namespace indexing
, typename Algorithms::index_param from
, typename Algorithms::index_param to)
{
Algorithms::erase (c, from, to);
Algorithms::erase_range (c, from, to);
}
};
}
@@ -183,6 +187,32 @@ indexing::slice_handler<Algorithms, Policy>
return boost::python::make_function (set_slice, policy);
}
/////////////////////////////////////////////////////////////////////////////
// Return a function object that implements the slice version of __delitem__
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
boost::python::object
indexing::slice_handler<Algorithms, Policy>
::make_delitem (Policy const &policy)
{
// should we try to get funky with policy::precall?
return boost::python::make_function (del_slice, policy);
}
/////////////////////////////////////////////////////////////////////////////
// Return a function object that implements extend
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
boost::python::object
indexing::slice_handler<Algorithms, Policy>
::make_extend (Policy const &policy)
{
// should we try to get funky with policy::precall?
return boost::python::make_function (extend, policy);
}
/////////////////////////////////////////////////////////////////////////////
// Implementation for the slice version of __getitem__
/////////////////////////////////////////////////////////////////////////////
@@ -233,7 +263,12 @@ indexing::slice_handler<Algorithms, Policy>
}
typedef typename Algorithms::container_traits traits;
typedef boost::python::extract<typename Algorithms::value_param> extractor;
// Try two kinds of extractors - the first is more efficient (using
// a reference to existing object, if possible and sensible) and the
// second allowing implicit conversions.
typedef boost::python::extract<typename Algorithms::value_param> extractor1;
typedef boost::python::extract<typename Algorithms::value_type> extractor2;
// Note: any error during this operation will probably leave the
// container partially updated. This can occur (for example) if the
@@ -250,7 +285,17 @@ indexing::slice_handler<Algorithms, Policy>
{
if (sl.inRange (index))
{
Algorithms::assign (c, index, extractor (iterPtr->current()));
extractor1 ex1 (iterPtr->current());
if (ex1.check())
{
Algorithms::assign (c, index, ex1);
}
else
{
Algorithms::assign (c, index, extractor2 (iterPtr->current()));
}
}
else if (sl.step() != 1)
@@ -266,9 +311,22 @@ indexing::slice_handler<Algorithms, Policy>
// Could optimize this in some cases (i.e. if the length of
// the replacement sequence is known)
maybe_insert<traits::has_insert>
::template apply<Algorithms> (c, index
, extractor (iterPtr->current()));
extractor1 ex1 (iterPtr->current());
if (ex1.check())
{
maybe_insert<traits::has_insert>
::template apply<Algorithms> (c, index, ex1);
Algorithms::assign (c, index, ex1);
}
else
{
maybe_insert<traits::has_insert>
::template apply<Algorithms>
(c, index, extractor2 (iterPtr->current()));
}
}
index += sl.step();
@@ -293,4 +351,41 @@ indexing::slice_handler<Algorithms, Policy>
}
}
/////////////////////////////////////////////////////////////////////////////
// Implementation for the slice version of __delitem__
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
void
indexing::slice_handler<Algorithms, Policy>
::del_slice (container &c, slice sl)
{
sl.setLength (Algorithms::size (c)); // Current length of our container
Algorithms::erase_range (c, sl.start(), sl.stop());
}
/////////////////////////////////////////////////////////////////////////////
// Implementation of extend
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
void
indexing::slice_handler<Algorithms, Policy>
::extend (container &c, boost::python::object values)
{
boost::python::object length
((boost::python::detail::new_reference
(PyInt_FromLong (Algorithms::size (c)))));
indexing::slice sl
((boost::python::detail::new_reference
(PySlice_New
(length.ptr()
, boost::python::object().ptr()
, boost::python::object().ptr()))));
set_slice (c, sl, values);
}
#endif // slice_handler_rmg_20030909_included

View File

@@ -22,14 +22,43 @@
# $Id$
#
from testsuite import Array, getArray
from testsuite import Array, getArray, IntWrapper, setTrace
setTrace (0)
a = getArray()
print a[0], a[1], a[2], [x for x in a], a[0:-2], a[-1:-3:-1], a[0:54:0]
print a[0], a[1], a[2], [x for x in a], a[0:-2], a[-1:-3:-1]
try:
a[0:54:0]
except ValueError, e:
print "Got expected ValueError:", e
pass
a[1] = 4
print a[0], a[1], a[2], [x for x in a], a[0:-2], a[-1:-3:-1]
print a[0:43]
print a[0:43] # Try index beyond length
# Try slice assignment with correct length
a[0:2] = [IntWrapper(-1), IntWrapper(-2)]
print [x for x in a]
# Try slice assignment with overlong sequence
try:
a[0:1] = [IntWrapper(-1), IntWrapper(-2)]
except TypeError, e:
print "Got expected TypeError:", e
pass
# Try slice assignment with short sequence
try:
a[0:3] = [IntWrapper(-1), IntWrapper(-2)]
except TypeError, e:
print "Got expected TypeError:", e
pass

View File

@@ -23,48 +23,89 @@
#
from indexing import *
import sys
trace(0)
setTrace(0)
def test_from_empty(v):
if hasattr(sys, "gettotalrefcount"):
def dumper() : print "refcount:", sys.gettotalrefcount()
maybe_dump_refcount = dumper
else:
def dumper() : pass
maybe_dump_refcount = dumper
def test_from_empty(v, outfile = sys.stdout):
# v.reserve (10);
print v
print >> outfile, v
v.append (IntWrapper (1))
v.append (IntWrapper (2))
v.append (IntWrapper (3))
print v[0], v[1], v[2]
print >> outfile, v[0], v[1], v[2]
try:
print v[0], v[1:][0], v[-1:][0]
print >> outfile, v[0], v[1:][0], v[-1:][0]
except Exception, e:
print e
print >> outfile, e
pass
copy = v[1]
print "copy is %s, v[1] is %s" % (copy, v[1])
print >> outfile, "copy is %s, v[1] is %s" % (copy, v[1])
v[1].increment()
print "copy is %s, v[1] is %s" % (copy, v[1])
print >> outfile, "copy is %s, v[1] is %s" % (copy, v[1])
v[1] = IntWrapper (5)
print "copy is %s, v[1] is %s" % (copy, v[1])
print >> outfile, "copy is %s, v[1] is %s" % (copy, v[1])
slice = v[1:2]
copy = slice[0]
print "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
print >> outfile, "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
v[1].increment()
print "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
print >> outfile, "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
v[1] = IntWrapper (7)
print "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
print >> outfile, "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
slice[0] = IntWrapper (9)
print "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
print >> outfile, "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
print "============="
# if hasattr(sys, "gettotalrefcount"):
# for x in range(20):
# v[:] = [1,2,3,4]
# maybe_dump_refcount()
# for x in range(9):
# v[:] = [1,2,3,4]
# maybe_dump_refcount()
print >> outfile, "============="
#test_from_empty (Vector_proxy())
class write_eater:
def write (self, str):
pass
# Run everything through once to settle reference counters
test_from_empty (Vector(), write_eater())
test_from_empty (ProxyVector(), write_eater())
test_from_empty (PointerVector(), write_eater())
test_from_empty ([], write_eater())
# Run again with output (and ref-count dumping, if possible)
maybe_dump_refcount()
test_from_empty (Vector())
maybe_dump_refcount()
test_from_empty (ProxyVector())
maybe_dump_refcount()
test_from_empty (PointerVector())
maybe_dump_refcount()
test_from_empty ([])
maybe_dump_refcount()

View File

@@ -36,6 +36,7 @@
#include <boost/python/implicit.hpp>
#include "iterator_pair.hpp"
#include "container_proxy.hpp"
indexing::iterator_pair<IntWrapper *> getArray()
{
@@ -63,7 +64,8 @@ BOOST_PYTHON_MODULE(testsuite)
boost::python::class_<IntWrapper> ("IntWrapper", boost::python::init<int>())
.def ("increment", &IntWrapper::increment)
.def ("__repr__", repr);
.def ("__repr__", repr)
.def ("__cmp__", compare)
;
typedef std::vector<int> Container1;
@@ -96,4 +98,9 @@ BOOST_PYTHON_MODULE(testsuite)
// deletes!
boost::python::class_<Container5>("Vector_ref")
.def (indexing::container_suite<Container5>::generate (boost::python::return_internal_reference<>()));
typedef container_proxy<std::vector<IntWrapper> > Container6;
boost::python::class_<Container6>("Vector_proxy")
.def (indexing::container_suite<Container6>::generate ());
}

View File

@@ -22,18 +22,60 @@
# $Id$
#
from testsuite import Vector
from testsuite import Vector, Vector_ref, setTrace
v = Vector()
def test_vector(v):
v.append(1)
v.append(2)
v.append(3)
v.append(1)
v.append(2)
v.append(3)
print v[0], v[1], v[2], [x for x in v]
print v[0], v[1], v[2], [x for x in v]
v[1] = 4
v[1] = 4
print v[0], v[1], v[2], [x for x in v], v[0:2]
print v[0], v[1], v[2], [x for x in v]
# Try slice assignment with equal lengths
v[0:2] = [9, 8]
print [x for x in v]
print v[0:2]
# Try slice assignment with shorter replacement
v[0:2] = [7]
print [x for x in v]
# Try slice assignment with longer replacement
v[0:1] = [6, 5, 4]
print [x for x in v]
# Try element deletion
del v[0]
print [x for x in v]
# Try slice deletion
del v[0:2]
print [x for x in v]
try:
del v[3]
except IndexError, e:
print "Got expected exception:", e
print [x for x in v]
del v[0:999]
print [x for x in v]
v.append (3)
print v[0]
del v[:]
print [x for x in v]
print "Plain vector:"
print "============="
test_vector (Vector())
print "Ref vector:"
print "==========="
setTrace(0)
test_vector (Vector_ref())

View File

@@ -2,7 +2,7 @@
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/implicit.hpp>
#include "container_proxy.hpp"
#include "container_suite.hpp"
using namespace boost::python;
@@ -23,11 +23,6 @@ std::string x_value(X const& x)
return "gotya " + x.s;
}
X *get_pointer (container_proxy<std::vector<X> >::value_type const &proxy)
{
return &(*proxy);
}
BOOST_PYTHON_MODULE(vector_indexing_suite_ext)
{
class_<X>("X")
@@ -35,6 +30,7 @@ BOOST_PYTHON_MODULE(vector_indexing_suite_ext)
.def(init<X>())
.def(init<std::string>())
.def("__repr__", &X::repr)
.def("__eq__", &X::operator==)
.def("reset", &X::reset)
.def("foo", &X::foo)
;
@@ -45,12 +41,8 @@ BOOST_PYTHON_MODULE(vector_indexing_suite_ext)
typedef std::vector<X> RawContainer;
typedef container_proxy<RawContainer> Container;
boost::python::register_ptr_to_python<Container::value_type>();
implicitly_convertible<X, Container::value_type>();
class_<Container>("XVec")
.def(vector_indexing_suite<Container, true>())
.def(indexing::container_suite<Container>::generate())
;
// Compile check only...

View File

@@ -28,14 +28,68 @@
#include <boost/python/def_visitor.hpp>
#include <boost/python/iterator.hpp>
#include <boost/bind.hpp>
#include <functional>
namespace indexing {
namespace detail {
template<typename PrecallPolicy>
struct precall_only : public boost::python::default_call_policies
{
// This policies struct uses default policies for everything
// except precall, which must be provided by the template
// argument.
precall_only () : mPrecall () { }
explicit precall_only (PrecallPolicy const &copy) : mPrecall (copy) { }
bool precall (PyObject *args) { return mPrecall.precall (args); }
bool precall (PyObject *args) const { return mPrecall.precall (args); }
private:
PrecallPolicy mPrecall;
};
}
//////////////////////////////////////////////////////////////////////////
// __len__ dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit>
struct maybe_add_len {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// __len__ real
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_len<true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("__len__", &Algorithms::size, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// __getitem__ dummy
//////////////////////////////////////////////////////////////////////////
template<IndexStyle>
struct maybe_add_getitem {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// __getitem__ no-slice
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_getitem<index_style_nonlinear> {
template<class PythonClass, class Algorithms, class Policy>
@@ -47,6 +101,10 @@ namespace indexing {
}
};
//////////////////////////////////////////////////////////////////////////
// __getitem__ with slice
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_getitem<index_style_linear> {
template<class PythonClass, class Algorithms, class Policy>
@@ -60,12 +118,20 @@ namespace indexing {
}
};
//////////////////////////////////////////////////////////////////////////
// __setitem__ dummy
//////////////////////////////////////////////////////////////////////////
template<IndexStyle>
struct maybe_add_setitem {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// __setitem__ no-slice
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_setitem<index_style_nonlinear> {
template<class PythonClass, class Algorithms, class Policy>
@@ -77,6 +143,10 @@ namespace indexing {
}
};
//////////////////////////////////////////////////////////////////////////
// __setitem__ with slice
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_setitem<index_style_linear> {
template<class PythonClass, class Algorithms, class Policy>
@@ -90,12 +160,62 @@ namespace indexing {
}
};
//////////////////////////////////////////////////////////////////////////
// __delitem__ dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit, IndexStyle syle>
struct maybe_add_delitem {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// __delitem__ no-slice
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_delitem<true, index_style_nonlinear> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("__delitem__", &Algorithms::erase_one, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// __delitem__ with slice
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_delitem<true, index_style_linear> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("__delitem__", &Algorithms::erase_one, policy);
pyClass.def ("__delitem__"
, slice_handler<Algorithms, Policy>::make_delitem (policy));
}
};
//////////////////////////////////////////////////////////////////////////
// __iter__ dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit>
struct maybe_add_iter {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// __iter__ real
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_iter<true> {
template<class PythonClass, class Algorithms, class Policy>
@@ -103,18 +223,29 @@ namespace indexing {
, Algorithms const &
, Policy const &policy)
{
// *FIXME* seperate precall and postcall portions of the
// policy (precall when generating the range object, postcall
// when returing from range.next())
pyClass.def ("__iter__"
, boost::python::range<Policy> (Algorithms::begin
, Algorithms::end));
}
};
//////////////////////////////////////////////////////////////////////////
// append dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit>
struct maybe_add_append {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// append real
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_append<true> {
template<class PythonClass, class Algorithms, class Policy>
@@ -126,6 +257,155 @@ namespace indexing {
}
};
//////////////////////////////////////////////////////////////////////////
// extend dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit>
struct maybe_add_extend {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// extend real
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_extend<true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("extend"
, slice_handler<Algorithms, Policy>::make_extend (policy));
}
};
//////////////////////////////////////////////////////////////////////////
// index dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit>
struct maybe_add_index {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// index real
//////////////////////////////////////////////////////////////////////////
namespace detail {
template<typename Algorithms>
typename Algorithms::index_type
get_index (typename Algorithms::container &c
, typename Algorithms::key_param key)
{
typename Algorithms::iterator temp (Algorithms::find (c, key));
if (temp == Algorithms::end(c))
{
PyErr_SetString (PyExc_ValueError
, "get_index: element not found");
boost::python::throw_error_already_set ();
}
return std::distance (Algorithms::begin (c), temp);
}
}
template<>
struct maybe_add_index<true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("index", detail::get_index<Algorithms>, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// count dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit, IndexStyle>
struct maybe_add_count {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// count real (sequences without indexing)
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_count<true, index_style_none> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("count", Algorithms::count, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// count real (sequences with indexing)
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_count<true, index_style_linear> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
// This is identical to the index_style_none version. Doing it
// this way avoids using a partial specialization for
// <true, *>
pyClass.def ("count", Algorithms::count, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// count real (associative containers). add has_key
//////////////////////////////////////////////////////////////////////////
namespace detail {
template<typename Algorithms>
bool has_key (typename Algorithms::container &c
, typename Algorithms::key_param key)
{
return Algorithms::find (c, key) != Algorithms::end (c);
}
}
template<>
struct maybe_add_count<true, index_style_nonlinear> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
// Nearest equivalent is has_key, since Python dictionaries
// have at most one value for a key.
pyClass.def ("has_key", detail::has_key<Algorithms>, policy);
// Maybe this makes sense for multimap or multiset. Then again,
// maybe they should always return a list of elements for a key?
pyClass.def ("count", Algorithms::count, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// Do-all visitor
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
class visitor
: public boost::python::def_visitor< visitor< Algorithms, Policy > >
@@ -136,23 +416,49 @@ namespace indexing {
typedef Algorithms algorithms;
typedef typename algorithms::container_traits traits;
visitor (Policy const &policy) : mPolicy (policy) { }
explicit visitor (Policy const &policy = Policy()) : mPolicy (policy) { }
template <class PythonClass>
void visit (PythonClass &pyClass) const
{
detail::precall_only<Policy> precallPolicy (mPolicy);
// Note - this will add __len__ for anything that can determine
// its size, even if that might be inefficient (e.g. have linear
// time complexity). It might be better to add a new feature
// selection flag to the container_traits to make this
// configurable.
maybe_add_len<traits::has_copyable_iter>
::apply (pyClass, algorithms(), precallPolicy);
maybe_add_getitem<traits::index_style>
::apply (pyClass, algorithms(), mPolicy);
maybe_add_setitem<traits::index_style>
::apply (pyClass, algorithms(), mPolicy);
maybe_add_delitem<traits::has_erase, traits::index_style>
::apply (pyClass, algorithms(), mPolicy);
maybe_add_iter<((traits::index_style != index_style_linear)
&& traits::has_copyable_iter)>
::apply (pyClass, algorithms(), mPolicy);
maybe_add_append<traits::has_push_back>
::apply (pyClass, algorithms(), mPolicy);
::apply (pyClass, algorithms(), precallPolicy);
maybe_add_extend<(traits::has_insert
&& traits::index_style == index_style_linear)>
::apply (pyClass, algorithms(), precallPolicy);
maybe_add_index<(traits::has_find
&& (traits::index_style == index_style_linear))>
::apply (pyClass, algorithms(), precallPolicy);
maybe_add_count<traits::has_find, traits::index_style>
::apply (pyClass, algorithms(), precallPolicy);
Algorithms::visitor_helper (pyClass, mPolicy);
}
};
}