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

Version 2 of the python indexing suite

[SVN r20288]
This commit is contained in:
Raoul Gough
2003-10-07 16:58:23 +00:00
parent 0b1e457c77
commit 6eeb6e6650
15 changed files with 3333 additions and 0 deletions

View File

@@ -0,0 +1,195 @@
// -*- mode:c++ -*-
//
// Header file algo_selector.hpp
//
// Automatic selection of container algorithms (and traits) for known
// container types (basically, all STL container instances, as well as
// iterator_pair instances).
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 9/11 rmg File creation
//
// $Id$
//
#ifndef algo_selector_rmg_20030911_included
#define algo_selector_rmg_20030911_included
#include <boost/python/suite/indexing/container_traits.hpp>
#include <boost/python/suite/indexing/algorithms.hpp>
// Definitions of supported types
#include <boost/python/suite/indexing/iterator_pair.hpp>
#include <boost/python/suite/indexing/container_proxy.hpp>
#include <set>
#include <map>
#include <list>
#include <deque>
#include <vector>
namespace boost { namespace python { namespace indexing {
/////////////////////////////////////////////////////////////////////////
// Automated algorithm and trait selection
/////////////////////////////////////////////////////////////////////////
namespace detail {
template<typename Container> struct selector_impl;
// selector_impl instances should include *two* publically
// accessible typedefs, one for the non-const version of the
// container, and one for the const version. This saves having to
// have two specializations of selector_impl for every kind of
// container.
// std::set
template <class Key, class Compare, class Allocator>
class selector_impl<std::set<Key, Compare, Allocator> >
{
typedef std::set<Key, Compare, Allocator> Container;
typedef set_traits<Container> mutable_traits;
typedef set_traits<Container const> const_traits;
public:
typedef set_algorithms<mutable_traits> mutable_algorithms;
typedef set_algorithms<const_traits> const_algorithms;
};
// std::multiset
template <class Key, class Compare, class Allocator>
class selector_impl<std::multiset<Key, Compare, Allocator> >
{
typedef std::multiset<Key, Compare, Allocator> Container;
typedef set_traits<Container> mutable_traits;
typedef set_traits<Container const> const_traits;
public:
typedef set_algorithms<mutable_traits> mutable_algorithms;
typedef set_algorithms<const_traits> const_algorithms;
};
// std::map
template <class Key, class T, class Compare, class Allocator>
class selector_impl<std::map<Key, T, Compare, Allocator> >
{
typedef std::map<Key, T, Compare, Allocator> Container;
typedef map_traits<Container> mutable_traits;
typedef map_traits<Container const> const_traits;
public:
typedef map_algorithms<mutable_traits> mutable_algorithms;
typedef map_algorithms<const_traits> const_algorithms;
};
// std::multimap
template <class Key, class T, class Compare, class Allocator>
class selector_impl<std::multimap<Key, T, Compare, Allocator> >
{
typedef std::multimap<Key, T, Compare, Allocator> Container;
typedef map_traits<Container> mutable_traits;
typedef map_traits<Container const> const_traits;
public:
typedef map_algorithms<mutable_traits> mutable_algorithms;
typedef map_algorithms<const_traits> const_algorithms;
};
// std::vector
template <class T, class Allocator>
class selector_impl<std::vector<T, Allocator> >
{
typedef std::vector<T, Allocator> Container;
typedef default_sequence_traits<Container> mutable_traits;
typedef default_sequence_traits<Container const> const_traits;
public:
typedef default_algorithms<mutable_traits> mutable_algorithms;
typedef default_algorithms<const_traits> const_algorithms;
};
// std::deque
template <class T, class Allocator>
class selector_impl<std::deque<T, Allocator> >
{
typedef std::deque<T, Allocator> Container;
typedef default_sequence_traits<Container> mutable_traits;
typedef default_sequence_traits<Container const> const_traits;
public:
typedef default_algorithms<mutable_traits> mutable_algorithms;
typedef default_algorithms<const_traits> const_algorithms;
};
// std::list
template <class T, class Allocator>
class selector_impl<std::list<T, Allocator> >
{
typedef std::list<T, Allocator> Container;
typedef default_sequence_traits<Container> mutable_traits;
typedef default_sequence_traits<Container const> const_traits;
public:
typedef list_algorithms<mutable_traits> mutable_algorithms;
typedef list_algorithms<const_traits> const_algorithms;
};
// Iterator ranges
template <typename Iterator>
class selector_impl<iterator_pair<Iterator> >
{
typedef iterator_pair<Iterator> Container;
typedef iterator_pair_traits<Container> mutable_traits;
typedef iterator_pair_traits<Container const> const_traits; // ?
public:
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
// Generic version (mutable containers)
template<class Container>
struct algo_selector
: public detail::selector_impl<Container>::mutable_algorithms
{
};
// Partial specialization for const containers
template<class Container>
struct algo_selector<Container const>
: public detail::selector_impl<Container>::const_algorithms
{
};
} } }
#endif // algo_selector_rmg_20030911_included

View File

@@ -0,0 +1,602 @@
// -*- mode:c++ -*-
//
// Header file algorithms.hpp
//
// Uniform interface layer for all containers.
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 9/11 rmg File creation from suite_utils.hpp
//
// $Id$
//
#ifndef algorithms_rmg_20030823_included
#define algorithms_rmg_20030823_included
#include <boost/python/suite/indexing/suite_utils.hpp>
#include <boost/type_traits.hpp>
#include <boost/python/errors.hpp>
#include <algorithm>
#include <stdexcept>
#include <limits>
#include <string>
namespace boost { namespace python { namespace indexing {
template<typename ContainerTraits>
struct default_algorithms
{
typedef ContainerTraits container_traits;
// Import typedefs from the container_traits for convenience
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;
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 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
, bool truncate = false);
// Throws std::out_of_range if necessary. If one_past is set, then
// indexes up to container.size() *inclusive* are allowed. If
// truncate is set, then out of bounds values are reset to the
// nearest in-bound value (and if none exists, throws an
// exception). If truncate is *not* set, then negative values index
// from the upper bound backwards and are bounds-checked.
};
/////////////////////////////////////////////////////////////////////////
// Special cases for std::list
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
struct list_algorithms : public default_algorithms<ContainerTraits>
{
private:
typedef default_algorithms<ContainerTraits> Parent;
public:
typedef typename Parent::container container;
// Use member functions for the following (hiding base class versions)
static void reverse (container &);
static void sort (container &);
// static void sort (container &, PyObject *);
};
/////////////////////////////////////////////////////////////////////////
// Base class for associative containers
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
struct assoc_algorithms : public default_algorithms<ContainerTraits>
{
private:
typedef default_algorithms<ContainerTraits> Parent;
public:
typedef typename Parent::iterator iterator;
typedef typename Parent::size_type size_type;
typedef typename Parent::container container;
typedef typename Parent::reference reference;
typedef typename Parent::key_param key_param;
typedef typename Parent::value_param value_param;
typedef typename Parent::index_param index_param;
static reference get (container &, index_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);
static bool contains (container &, key_param);
protected:
static iterator find_or_throw (container &, index_param);
};
/////////////////////////////////////////////////////////////////////////
// Special case for sets
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
struct set_algorithms : public assoc_algorithms<ContainerTraits>
{
private:
typedef assoc_algorithms<ContainerTraits> Parent;
public:
typedef typename Parent::container container;
typedef typename Parent::value_param value_param;
typedef typename Parent::index_param index_param;
static void assign (container &, index_param, value_param);
static void insert (container &, index_param);
};
/////////////////////////////////////////////////////////////////////////
// Special case for map
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
struct map_algorithms : public assoc_algorithms<ContainerTraits>
{
private:
typedef assoc_algorithms<ContainerTraits> Parent;
public:
typedef typename Parent::container container;
typedef typename Parent::reference reference;
typedef typename Parent::index_param index_param;
typedef typename Parent::value_param value_param;
static reference get (container &, index_param);
// Version to return only the mapped type
static void assign (container &, index_param, value_param);
static void insert (container &, index_param, value_param);
};
/////////////////////////////////////////////////////////////////////////
// Get the size of a container
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename default_algorithms<ContainerTraits>::size_type
default_algorithms<ContainerTraits>::size (container &c)
{
return c.size();
}
/////////////////////////////////////////////////////////////////////////
// Range check an index and throw out_of_range if necessary
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename default_algorithms<ContainerTraits>::size_type
default_algorithms<ContainerTraits>::bounds_check (container &c
, index_param ix
, char const *msg
, bool one_past
, bool truncate)
{
size_type bound = size(c) + (one_past ? 1 : 0);
size_type result;
if (truncate)
{
if (ix < 0)
{
result = 0;
}
else
{
result = ix;
if ((result >= bound) && (bound > 0))
{
result = bound - 1;
}
}
}
else if (ix < 0)
{
if (size_type(-ix) > bound)
{
throw std::out_of_range (msg);
}
result = bound + ix;
}
else
{
result = ix;
}
if (result >= bound)
{
throw std::out_of_range (msg);
}
return result;
}
/////////////////////////////////////////////////////////////////////////
// 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);
}
/////////////////////////////////////////////////////////////////////////
// Find an element and return its index (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename default_algorithms<ContainerTraits>::size_type
default_algorithms<ContainerTraits>::get_index (container &c
, key_param key)
{
iterator temp (find (c, key));
if (temp == end(c))
{
PyErr_SetString (PyExc_ValueError
, "get_index: element not found");
boost::python::throw_error_already_set ();
}
return std::distance (begin (c), temp);
}
/////////////////////////////////////////////////////////////////////////
// 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);
}
/////////////////////////////////////////////////////////////////////////
// Check whether a container contains the given element (std algo ver)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
bool
default_algorithms<ContainerTraits>::contains (container &c
, key_param key)
{
return find (c, key) != end(c);
}
/////////////////////////////////////////////////////////////////////////
// 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[bounds_check (c, ix, "get")];
}
/////////////////////////////////////////////////////////////////////////
// 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[bounds_check (c, ix, "assign")] = 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)
{
iterator insert_pos (c.begin());
// Index may range up to c.size() inclusive to allow inserting at end
std::advance (insert_pos, bounds_check (c, i, "insert", true, true));
c.insert (insert_pos, v);
}
/////////////////////////////////////////////////////////////////////////
// Erase between given indexes in the container (generic version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
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
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 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));
}
/////////////////////////////////////////////////////////////////////////
// Visitor helper function (default version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
template<typename PythonClass, typename Policy>
void
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 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();
}
/////////////////////////////////////////////////////////////////////////
// Index into a container (associative version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename assoc_algorithms<ContainerTraits>::reference
assoc_algorithms<ContainerTraits>::get (container &c, index_param ix)
{
return *find_or_throw (c, ix);
}
/////////////////////////////////////////////////////////////////////////
// Index into a container (map version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename map_algorithms<ContainerTraits>::reference
map_algorithms<ContainerTraits>::get (container &c, index_param ix)
{
return find_or_throw (c, ix)->second;
}
/////////////////////////////////////////////////////////////////////////
// Erase elements with the given key (associative version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
assoc_algorithms<ContainerTraits>::erase_one (container &c
, key_param key)
{
if (c.erase (key) == 0)
{
PyErr_SetString (PyExc_ValueError
, "Container does not hold value to be erased");
boost::python::throw_error_already_set ();
}
}
/////////////////////////////////////////////////////////////////////////
// Assign a value at a particular index (set version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
set_algorithms<ContainerTraits>::assign (container &c
, index_param ix
, value_param val)
{
insert (c, ix); // Ignore dummy value parameter
}
/////////////////////////////////////////////////////////////////////////
// Insert an element into a set
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
set_algorithms<ContainerTraits>::insert (container &c
, index_param ix)
{
if (!c.insert (ix).second)
{
PyErr_SetString (PyExc_ValueError
, "Set already holds value for insertion");
boost::python::throw_error_already_set ();
}
}
/////////////////////////////////////////////////////////////////////////
// Assign a value at a particular index (map version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
map_algorithms<ContainerTraits>::assign (container &c
, index_param ix
, value_param val)
{
c[ix] = val; // Handles overwrite and insert
}
/////////////////////////////////////////////////////////////////////////
// Insert a new key, value pair into a map
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void
map_algorithms<ContainerTraits>::insert (container &c
, index_param ix
, value_param val)
{
typedef std::pair
<typename container_traits::index_type
, typename container_traits::value_type>
pair_type;
// Can't use std::make_pair, because param types may be references
if (!c.insert (pair_type (ix, val)).second)
{
PyErr_SetString (PyExc_ValueError
, "Map already holds value for insertion");
boost::python::throw_error_already_set ();
}
}
/////////////////////////////////////////////////////////////////////////
// Find an element in an associative container
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename assoc_algorithms<ContainerTraits>::iterator
assoc_algorithms<ContainerTraits>::find (container &c, key_param key)
{
return c.find (key);
}
/////////////////////////////////////////////////////////////////////////
// Find an element in an associative container
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
bool
assoc_algorithms<ContainerTraits>::contains (container &c
, key_param key)
{
return find (c, key) != end(c);
}
/////////////////////////////////////////////////////////////////////////
// Find an element in an associative container - throw an exception if
// not found
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename assoc_algorithms<ContainerTraits>::iterator
assoc_algorithms<ContainerTraits>::find_or_throw (container &c
, index_param ix)
{
iterator iter = find (c, ix);
if (iter == end(c))
{
PyErr_SetString (PyExc_ValueError
, "associative container: key not found");
boost::python::throw_error_already_set ();
}
return iter;
}
/////////////////////////////////////////////////////////////////////////
// Count occurances of an element in a container (associative version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename assoc_algorithms<ContainerTraits>::size_type
assoc_algorithms<ContainerTraits>::count (container &c
, key_param key)
{
return c.count (key);
}
} } }
#endif // algorithms_rmg_20030823_included

View File

@@ -0,0 +1,543 @@
// -*- mode:c++; switch-modules-target: "testcontprox.cpp" -*-
//
// Header file container_proxy.hpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 8/26 rmg File creation
//
// $Id$
//
#ifndef container_proxy_rmg_20030826_included
#define container_proxy_rmg_20030826_included
#include <boost/python/suite/indexing/shared_proxy_impl.hpp>
#include <boost/python/suite/indexing/element_proxy.hpp>
#include <map>
#include <memory>
#include <cassert>
#include <iterator>
#include <boost/shared_ptr.hpp>
#include <boost/iterator/iterator_traits.hpp>
namespace boost { namespace python { namespace indexing {
template<typename T> struct identity {
typedef T held_type;
static T & get(T & obj) { return obj; }
static T const & get(T const & obj) { return obj; }
static T create () { return T(); }
static T copy (T const &copy) { return copy; }
static void assign (T &to, T const &from) { to = from; }
static void pre_destruction (T &) { }
};
template<typename P> struct deref {
typedef P held_type;
typedef typename boost::iterator_value<P>::type value;
static value & get (P & ptr) { return *ptr; }
static value const & get (P const & ptr) { return *ptr; }
static P create () { return P(); }
static P copy (P const &copy) { return copy; }
static void assign (P &to, P const &from) { to = from; }
static void pre_destruction (P &) { }
};
template<class Container
, class Holder = identity<Container> >
class container_proxy
{
typedef container_proxy<Container, Holder> self_type;
typedef typename Container::iterator raw_iterator;
typedef std::iterator_traits<raw_iterator> raw_iterator_traits;
template<class C> friend class shared_proxy_impl;
public:
typedef typename Holder::held_type held_type;
typedef typename Container::size_type size_type;
typedef typename Container::difference_type difference_type;
typedef shared_proxy_impl<self_type> shared_proxy;
typedef typename Container::value_type raw_value_type;
typedef element_proxy<self_type> value_type;
typedef value_type reference; // Already has ref. semantics
typedef const_element_proxy<self_type> const_value_type;
typedef const_value_type const_reference; // Ref. semantics
public:
struct iterator
{
typedef typename raw_iterator_traits::difference_type difference_type;
typedef std::random_access_iterator_tag iterator_category;
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) { }
iterator (container_proxy *p, raw_iterator iter)
: ptr (p), index (iter - p->raw_container().begin())
{
}
reference operator*() const { return ptr->at(index); }
pointer operator->() const { return &ptr->at(index); }
reference operator[](size_type s) { return ptr->at (index + s); }
iterator &operator++ () { ++index; return *this; }
iterator operator++ (int) { iterator temp(*this); ++index; return temp; }
iterator &operator+= (size_type s) { index += s; return *this; }
iterator &operator-- () { --index; return *this; }
iterator operator-- (int) { iterator temp(*this); --index; return temp; }
iterator &operator-= (size_type s) { index -= s; return *this; }
iterator operator+ (size_type s) const { return iterator(*this) += s; }
iterator operator- (size_type s) const { return iterator(*this) -= s; }
difference_type operator- (iterator i) const { return index - i.index; }
bool operator== (iterator const &other) const {
return (ptr == other.ptr) && (index == other.index);
}
bool operator!= (iterator const &other) const { return !(*this == other); }
bool operator< (iterator const &other) const {
return index < other.index;
}
bool operator> (iterator const &other) const {
return index > other.index;
}
// public:
// Extensions to the normal iterator interface
// void replace (value_type const &copy) { ptr->replace (index, copy); }
public:
friend class container_proxy;
container_proxy *ptr;
size_type index;
};
public:
// Constructors
container_proxy ();
explicit container_proxy (held_type const &h);
template<typename Iter> container_proxy (Iter, Iter);
container_proxy (container_proxy const &);
container_proxy &operator= (container_proxy const &);
~container_proxy ();
Container const &raw_container() const; // OK to expose const reference
reference at (size_type index);
const_reference at (size_type index) const;
reference operator[] (size_type index) { return at(index); }
const_reference operator[] (size_type index) const { return at(index); }
size_type size() const { return raw_container().size(); }
size_type capacity() const { return raw_container().capacity(); }
void reserve(size_type s) { raw_container().reserve(s); }
public:
iterator begin() { return iterator (this, 0); }
iterator end() { return iterator (this, raw_container().size()); }
iterator erase (iterator);
iterator erase (iterator, iterator);
iterator insert (iterator, raw_value_type const &);
template<typename Iter> void insert (iterator, Iter, Iter);
void push_back (raw_value_type const &copy) { insert (end(), copy); }
value_type pop_back () {
value_type result = at (end() - 1);
erase (end() - 1);
return result;
}
public:
// Proxies for a given index must be detached before overwriting
// that container element.
void detach_proxy (size_type index);
void detach_proxies (size_type from, size_type to);
void detach_proxies (iterator from, iterator to);
public:
// Convenient replacement of elements (automatic proxy detachment)
void replace (size_type index, raw_value_type const &);
template<typename Iter> void replace (size_type index, Iter, Iter);
private:
// Overloads for insertions with/without useful std::distance
template<typename Iter>
void insert (iterator, Iter, Iter, std::forward_iterator_tag);
template<typename Iter>
void insert (iterator, Iter, Iter, std::input_iterator_tag);
private:
typedef boost::shared_ptr<shared_proxy> pointer_impl;
typedef std::map<size_type, pointer_impl> MapType;
typedef typename MapType::iterator MapIterator;
typedef typename MapType::reverse_iterator ReverseIterator;
typedef typename MapType::value_type MapEntry;
private:
Container &raw_container();
static void detach_if_shared (MapEntry const &);
template<typename Iter>
void adjustIndexes (Iter, Iter, long offset);
void erase_helper (MapIterator);
void erase_helper (ReverseIterator);
private:
held_type myHeldObj;
MapType myMap;
};
template<class Container, class Holder>
container_proxy<Container, Holder>
::container_proxy ()
: myHeldObj ()
, myMap ()
{
}
template<class Container, class Holder>
container_proxy<Container, Holder>
::container_proxy (held_type const &heldType)
: myHeldObj (heldType)
, myMap ()
{
}
template<class Container, class Holder>
template<typename Iter>
container_proxy<Container, Holder>
::container_proxy (Iter start, Iter finish)
: myHeldObj (Holder::create())
, myMap ()
{
insert (begin(), start, finish);
}
template<class Container, class Holder>
container_proxy<Container, Holder>
::container_proxy (container_proxy const &copy)
: myHeldObj (Holder::copy (copy.myHeldObj))
, myMap () // Do *not* duplicate map
{
}
template<class Container, class Holder>
container_proxy<Container, Holder> &
container_proxy<Container, Holder>
::operator= (container_proxy const &copy)
{
// All of our contained values are about to be dis-owned
std::for_each (myMap.begin(), myMap.end(), detach_if_shared);
myMap.clear();
Holder::assign (myHeldObj, copy.myHeldObj);
}
template<class Container, class Holder>
container_proxy<Container, Holder>
::~container_proxy ()
{
// All of our contained values are about to be dis-owned
std::for_each (myMap.begin(), myMap.end(), detach_if_shared);
Holder::pre_destruction (myHeldObj);
}
template<class Container, class Holder>
Container &
container_proxy<Container, Holder>
::raw_container ()
{
return Holder::get (myHeldObj);
}
template<class Container, class Holder>
Container const &
container_proxy<Container, Holder>
::raw_container () const
{
return Holder::get (myHeldObj);
}
template<class Container, class Holder>
typename container_proxy<Container, Holder>::reference
container_proxy<Container, Holder>
::at (size_type index)
{
pointer_impl &entry = myMap[index];
if (!entry.get())
{
entry.reset (new shared_proxy (this, index));
}
return reference (entry);
}
template<class Container, class Holder>
typename container_proxy<Container, Holder>::const_reference
container_proxy<Container, Holder>
::at (size_type index) const
{
// const_cast allows insertion into map. Maybe this is wrong, and
// there can be no const-version of at. Alternatively, maybe
// the map member variable should be declared mutable.
container_proxy *mutable_this = const_cast<container_proxy *>(this);
return const_reference (mutable_this->at (index));
}
template<class Container, class Holder>
void
container_proxy<Container, Holder>
::replace (size_type index, raw_value_type const &copy)
{
detach_proxy (index);
raw_container().at(index) = copy;
}
template<class Container, class Holder>
template<typename Iter>
void
container_proxy<Container, Holder>
::replace (size_type index, Iter from, Iter to)
{
while (from != to)
{
replace (index++, *from++);
}
}
template<class Container, class Holder>
typename container_proxy<Container, Holder>::iterator
container_proxy<Container, Holder>
::erase (iterator iter)
{
return erase (iter, iter + 1);
}
template<class Container, class Holder>
typename container_proxy<Container, Holder>::iterator
container_proxy<Container, Holder>
::erase (iterator from, iterator to)
{
assert (from.ptr == this);
assert (to.ptr == this);
size_type deleting = to.index - from.index;
MapIterator erase_begin = myMap.lower_bound (from.index);
MapIterator erase_end = myMap.lower_bound (to.index);
// Detach any proxies for the soon-to-be-erased elements
std::for_each (erase_begin, erase_end, detach_if_shared);
myMap.erase (erase_begin, erase_end); // Note: erase_end remains valid
// Adjust the indexes of any following proxies
adjustIndexes (erase_end, myMap.end(), -deleting);
// Erase the elements from the real container
raw_iterator result
= raw_container().erase (raw_container().begin() + from.index
, raw_container().begin() + to.index);
return iterator (this, result);
}
template<class Container, class Holder>
typename container_proxy<Container, Holder>::iterator
container_proxy<Container, Holder>
::insert (iterator iter, raw_value_type const &copy)
{
assert (iter.ptr == this);
// Adjust indexes (backwards) down to iter.index
adjustIndexes (myMap.rbegin()
, ReverseIterator (myMap.lower_bound (iter.index))
, 1);
// Insert the element into the real container
raw_iterator result
= raw_container().insert (raw_container().begin() + iter.index, copy);
return iterator (this, result);
}
template<class Container, class Holder>
template<typename Iter>
void
container_proxy<Container, Holder>
::insert (iterator iter, Iter from, Iter to)
{
// Forward insertion to the right overloaded version
typedef typename std::iterator_traits<Iter>::iterator_category category;
insert (iter, from, to, category());
}
template<class Container, class Holder>
template<typename Iter>
void
container_proxy<Container, Holder>
::insert (iterator iter, Iter from, Iter to, std::forward_iterator_tag)
{
// insert overload for iterators where we can get distance()
assert (iter.ptr == this);
// Adjust indexes (backwards) down to iter.index
adjustIndexes (myMap.rbegin()
, ReverseIterator (myMap.lower_bound (iter.index))
, std::distance (from, to));
// Insert the element into the real container
raw_container().insert (raw_container().begin() + iter.index, from, to);
}
template<class Container, class Holder>
template<typename Iter>
void
container_proxy<Container, Holder>
::insert (iterator iter, Iter from, Iter to, std::input_iterator_tag)
{
// insert overload for iterators where we *can't* get distance()
// so just insert elements one at a time
while (from != to)
{
iter = insert (iter, *from++) + 1;
}
}
template<class Container, class Holder>
void
container_proxy<Container, Holder>
::detach_if_shared (MapEntry const &ent)
{
if (!ent.second.unique())
{
ent.second->detach();
}
// If the pointer isn't shared, don't bother causing a copy of the
// container element, since the proxy is about to be deleted.
}
template<class Container, class Holder>
void
container_proxy<Container, Holder>
::detach_proxy (size_type index)
{
MapIterator iter = myMap.find (index);
if (iter != myMap.end())
{
detach_if_shared (*iter);
myMap.erase (iter);
}
}
template<class Container, class Holder>
void
container_proxy<Container, Holder>
::detach_proxies (size_type fromIndex, size_type toIndex)
{
MapIterator from = myMap.lower_bound (fromIndex);
MapIterator to = myMap.lower_bound (toIndex);
std::for_each (from, to, detach_if_shared);
myMap.erase (from, to);
}
template<class Container, class Holder>
void
container_proxy<Container, Holder>
::detach_proxies (iterator from, iterator to)
{
assert (from.ptr == this);
assert (to.ptr == this);
detach_proxies (from.index, to.index);
}
template<class Container, class Holder>
template<typename Iter>
void
container_proxy<Container, Holder>
::adjustIndexes (Iter from, Iter to, long offset)
{
// Adjust indexes in the given range of proxies by the given offset.
// The adjustment is done by erasing and re-inserting the entries
// in the map.
//
// Could provide a hint iterator to the map insertion calls, except
// in the case that "from" is right at the start of the container
// (the hint must be the element *before* the one to be inserted,
// and there is no element before the first one). This would mean
// additional complexity to deal with the special case somehow.
while (from != to)
{
Iter next (from);
++next; // Find next element before invalidating the current one
pointer_impl ptr (from->second); // Copy the shared pointer
erase_helper (from); // Remove the map copy of it
if (!ptr.unique())
{
// Reinsert only if there are other pointers "out there"
// referring to the shared proxy
ptr->myIndex += offset;
myMap.insert (typename MapType::value_type (ptr->myIndex, ptr));
}
from = next;
}
}
template<class Container, class Holder>
void
container_proxy<Container, Holder>
::erase_helper (MapIterator iter)
{
myMap.erase (iter);
}
template<class Container, class Holder>
void
container_proxy<Container, Holder>
::erase_helper (ReverseIterator iter)
{
++iter;
myMap.erase (iter.base());
}
} } }
#endif // container_proxy_rmg_20030826_included

View File

@@ -0,0 +1,46 @@
// -*- mode:c++ -*-
//
// Header file container_suite.hpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 8/23 rmg File creation
// 2003/ 9/ 8 rmg Extracted trait facilities into container_traits.hpp
//
// $Id$
//
#ifndef container_suite_rmg_20030823_included
#define container_suite_rmg_20030823_included
#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 boost::python::return_value_policy<boost::python::return_by_value>
default_container_policies;
template<class Container, class Algorithms = algo_selector<Container> >
struct container_suite
: public visitor<Algorithms, default_container_policies>
{
typedef Algorithms algorithms;
template<typename Policy>
static visitor<Algorithms, Policy> with_policies (Policy const &policy)
{
return visitor <Algorithms, Policy> (policy);
}
};
} } }
#endif // container_suite_rmg_20030823_included

View File

@@ -0,0 +1,196 @@
// -*- mode:c++ -*-
//
// 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
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 8/23 rmg File creation as container_suite.hpp
// 2003/ 9/ 8 rmg Renamed container_traits.hpp
//
// $Id$
//
#ifndef container_traits_rmg_20030823_included
#define container_traits_rmg_20030823_included
#include <boost/python/suite/indexing/suite_utils.hpp>
#include <boost/python/suite/indexing/iterator_traits.hpp>
#include <boost/python/suite/indexing/value_traits.hpp>
#include <boost/type_traits.hpp>
#include <boost/call_traits.hpp>
namespace boost { namespace python { 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 base_type::value_type value_type; // insert, etc.
typedef typename base_type::value_type key_type; // find, count, ...
typedef typename make_signed<size_type>::type index_type;
// at(), operator[]. Signed to support Python -ve indexes
typedef typename boost::call_traits<value_type>::param_type value_param;
typedef typename boost::call_traits<key_type>::param_type key_param;
typedef typename boost::call_traits<index_type>::param_type index_param;
// *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 base_container_traits<IteratorPair>
{
};
/////////////////////////////////////////////////////////////////////////
// Default container traits - almost all "real" containers would meet
// at least these requirements
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct default_container_traits : public base_container_traits<Container>
{
BOOST_STATIC_CONSTANT (bool, has_insert = is_mutable);
BOOST_STATIC_CONSTANT (bool, has_erase = is_mutable);
};
/////////////////////////////////////////////////////////////////////////
// Sequences (list, deque, vector)
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct default_sequence_traits : public default_container_traits<Container>
{
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 typename boost::call_traits<value_type>::param_type value_param;
typedef typename boost::call_traits<key_type>::param_type key_param;
typedef value_traits<reference> value_traits_;
// Get value_traits for the reference type (i.e. element_proxy)
// to get the custom visitor_helper
};
/////////////////////////////////////////////////////////////////////////
// Associative containers set and multiset
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct set_traits : public default_container_traits<Container>
{
// *FIXME* handle const sets
typedef void value_type; // index_type only (?)
typedef typename Container::key_type index_type; // operator[]
typedef typename Container::key_type key_type; // find, count, ...
typedef void * value_param;
typedef typename boost::call_traits<key_type>::param_type key_param;
typedef typename boost::call_traits<index_type>::param_type index_param;
BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_nonlinear);
BOOST_STATIC_CONSTANT (bool, has_find = true);
};
/////////////////////////////////////////////////////////////////////////
// Associative containers map and multimap
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct map_traits : public default_container_traits<Container>
{
// *FIXME* handle const maps
typedef typename Container::mapped_type value_type;
typedef value_type & reference;
typedef typename Container::key_type index_type; // operator[]
typedef typename Container::key_type key_type; // find, count, ...
typedef typename boost::call_traits<value_type>::param_type value_param;
typedef typename boost::call_traits<key_type>::param_type key_param;
typedef typename boost::call_traits<index_type>::param_type index_param;
BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_nonlinear);
BOOST_STATIC_CONSTANT (bool, has_find = true);
BOOST_STATIC_CONSTANT (bool, is_reorderable = false);
};
} } }
/////////////////////////////////////////////////////////////////////////
// Visitor helper function (foward to value_traits_ version)
/////////////////////////////////////////////////////////////////////////
template<typename Container>
template<typename PythonClass, typename Policy>
void
boost::python::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

@@ -0,0 +1,191 @@
// -*- mode:c++ -*-
//
// Header file element_proxy.hpp
//
// Proxy objects for invidivual elements in a container wrapped by
// container_proxy
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 9/15 rmg File creation from container_proxy.hpp
//
// $Id$
//
#ifndef element_proxy_rmg_20030915_included
#define element_proxy_rmg_20030915_included
#include <boost/python/suite/indexing/shared_proxy_impl.hpp>
#include <boost/python/suite/indexing/value_traits.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/get_pointer.hpp>
#include <boost/python/implicit.hpp>
#include <boost/python/register_ptr_to_python.hpp>
namespace boost { namespace python { namespace indexing {
template<typename ContainerProxy>
class element_proxy
{
template<typename T> friend struct const_element_proxy;
typedef ContainerProxy container_proxy;
typedef typename container_proxy::shared_proxy proxy_type;
typedef boost::shared_ptr<proxy_type> proxy_pointer;
typedef typename container_proxy::raw_value_type raw_value_type;
typedef typename container_proxy::size_type size_type;
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
};
template<typename ContainerProxy>
struct const_element_proxy
{
typedef ContainerProxy container_proxy;
typedef typename container_proxy::shared_proxy proxy_type;
typedef boost::shared_ptr<proxy_type> proxy_pointer;
typedef typename container_proxy::raw_value_type raw_value_type;
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<container_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
};
} } }
namespace boost
{
template<typename ContainerProxy>
typename ContainerProxy::raw_value_type *
get_pointer (python::indexing::element_proxy<ContainerProxy> const &proxy)
{
return &(*proxy);
}
}
namespace boost { namespace python { namespace indexing {
template<typename ContainerProxy>
struct value_traits<element_proxy<ContainerProxy> >
: public value_traits<typename ContainerProxy::raw_value_type>
{
template<typename PythonClass, typename Policy>
static void visitor_helper (PythonClass &, Policy const &)
{
typedef element_proxy<ContainerProxy> element_proxy_;
typedef typename ContainerProxy::raw_value_type raw_value_type;
boost::python::register_ptr_to_python<element_proxy_>();
boost::python::implicitly_convertible<raw_value_type, element_proxy_>();
}
};
} } }
#endif // element_proxy_rmg_20030915_included

View File

@@ -0,0 +1,132 @@
// -*- mode:c++ -*-
//
// Header file iterator_pair.hpp
//
// Emulate an STL container using a pair of iterators. Doesn't support
// insertion or deletion, for the obvious reasons.
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 9/ 9 rmg File creation
//
// $Id$
//
#ifndef iterator_pair_rmg_20030909_included
#define iterator_pair_rmg_20030909_included
#include <iterator>
#include <stdexcept>
#include <algorithm>
#include <boost/type_traits.hpp>
namespace boost { namespace python { namespace indexing {
template<typename Iterator>
class iterator_pair
{
private:
typedef typename boost::call_traits<Iterator>::param_type iterator_param;
typedef std::iterator_traits<Iterator> std_traits;
public:
typedef typename std_traits::reference reference;
typedef Iterator iterator;
typedef typename std_traits::difference_type size_type;
typedef typename std_traits::difference_type difference_type;
typedef typename std_traits::value_type value_type;
typedef typename std_traits::pointer pointer;
// Can't provide: const_iterator, allocator_type, reverse_iterator
// or const_reverse_iterator. Could probably provide (but don't)
// const_reference and const_pointer. These would be the same
// as reference and pointer if Iterator is itself a const_iterator.
public:
iterator_pair (iterator_param, iterator_param);
iterator begin() const;
iterator end() const;
public:
// Only sensible for random_access iterators
size_type size () const;
reference operator[] (size_type) const;
reference at (size_type) const;
private:
iterator myBegin;
iterator myEnd;
};
template<typename Iterator>
iterator_pair<Iterator>::iterator_pair (iterator_param begin
, iterator_param end)
: myBegin (begin)
, myEnd (end)
{
}
template<typename Iterator>
typename iterator_pair<Iterator>::iterator
iterator_pair<Iterator>::begin() const
{
return myBegin;
}
template<typename Iterator>
typename iterator_pair<Iterator>::iterator
iterator_pair<Iterator>::end() const
{
return myEnd;
}
template<typename Iterator>
typename iterator_pair<Iterator>::size_type
iterator_pair<Iterator>::size() const
{
return std::distance (begin(), end());
}
template<typename Iterator>
typename iterator_pair<Iterator>::reference
iterator_pair<Iterator>::operator[](size_type index) const
{
iterator temp (begin());
std::advance (temp, index);
return *temp;
}
template<typename Iterator>
typename iterator_pair<Iterator>::reference
iterator_pair<Iterator>::at (size_type index) const
{
if (index >= size())
{
throw std::out_of_range
(std::string ("iterator_pair: index out of range"));
}
else
{
return (*this)[index];
}
}
template<typename T, std::size_t N>
T *begin (T(&array)[N]) {
return array;
}
template<typename T, std::size_t N>
T *end (T(&array)[N]) {
return array + N;
}
} } }
#endif // iterator_pair_rmg_20030909_included

View File

@@ -0,0 +1,148 @@
// -*- mode:c++ -*-
//
// Header file iterator_traits.hpp
//
// Traits information about iterators for use in determining what
// Python methods to support for a container.
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 8/23 rmg File creation as iterator_suite.hpp
// 2003/ 9/12 rmg Renamed iterator_traits.hpp
//
// $Id$
//
#ifndef iterator_traits_rmg_20030823_included
#define iterator_traits_rmg_20030823_included
#include <boost/python/suite/indexing/suite_utils.hpp>
#include <iterator>
#include <boost/call_traits.hpp>
#include <boost/type_traits.hpp>
namespace boost { namespace python { namespace indexing {
enum IndexStyle {
index_style_none // No random access (iteration only)
, index_style_nonlinear // Random access by key (no slicing)
, index_style_linear // Random access by integer index (allows slicing)
};
//////////////////////////////////////////////////////////////////////////
// Indexing traits for containers based on iterator pairs
//////////////////////////////////////////////////////////////////////////
template<typename Iterator>
struct input_iterator_traits
{
private:
typedef std::iterator_traits<Iterator> std_traits;
public:
typedef Iterator iterator;
typedef typename std_traits::value_type value_type;
typedef typename std_traits::reference reference;
typedef typename std_traits::difference_type difference_type;
BOOST_STATIC_CONSTANT (bool, has_copyable_iter = false);
BOOST_STATIC_CONSTANT (bool, is_reorderable = false);
BOOST_STATIC_CONSTANT (bool, has_mutable_ref
= is_mutable_ref<reference>::value);
BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_none);
};
template<typename Iterator>
struct forward_iterator_traits
: public input_iterator_traits<Iterator>
{
BOOST_STATIC_CONSTANT (bool, has_copyable_iter = true);
};
template<typename Iterator>
struct bidirectional_iterator_traits
: public forward_iterator_traits<Iterator>
{
BOOST_STATIC_CONSTANT (bool, is_reorderable = has_mutable_ref);
};
template<typename Iterator>
struct random_access_iterator_traits
: public bidirectional_iterator_traits<Iterator>
{
BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_linear);
};
namespace iterator_detail {
typedef char input_iter_sizer[1];
typedef char forward_iter_sizer[2];
typedef char bidirectional_iter_sizer[3];
typedef char random_access_iter_sizer[4];
input_iter_sizer &sizer (std::input_iterator_tag const &);
forward_iter_sizer &sizer (std::forward_iterator_tag const &);
bidirectional_iter_sizer &sizer (std::bidirectional_iterator_tag const &);
random_access_iter_sizer &sizer (std::random_access_iterator_tag const &);
template<size_t Size> struct traits_by_size { };
template<>
struct traits_by_size<sizeof(input_iter_sizer)> {
template<typename Iterator>
struct traits {
typedef input_iterator_traits<Iterator> type;
};
};
template<>
struct traits_by_size<sizeof(forward_iter_sizer)> {
template<typename Iterator>
struct traits {
typedef forward_iterator_traits<Iterator> type;
};
};
template<>
struct traits_by_size<sizeof(bidirectional_iter_sizer)> {
template<typename Iterator>
struct traits {
typedef bidirectional_iterator_traits<Iterator> type;
};
};
template<>
struct traits_by_size<sizeof(random_access_iter_sizer)> {
template<typename Iterator>
struct traits {
typedef random_access_iterator_traits<Iterator> type;
};
};
template<typename Iterator>
class traits_by_category {
typedef typename std::iterator_traits<Iterator>::iterator_category
iterator_category;
BOOST_STATIC_CONSTANT (size_t, size
= sizeof(sizer(iterator_category())));
public:
typedef typename traits_by_size<size>::traits<Iterator>::type type;
};
}
template<typename Iterator>
struct iterator_traits
: public iterator_detail::traits_by_category<Iterator>::type
{
};
} } }
#endif // iterator_traits_rmg_20030823_included

View File

@@ -0,0 +1,65 @@
// -*- mode:c++ -*-
//
// Header file python_iterator.hpp
//
// Handy Python iterable iterators
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 9/10 rmg File creation
//
// $Id$
//
#ifndef python_iterator_rmg_20030910_included
#define python_iterator_rmg_20030910_included
#include <boost/python/object.hpp>
#include <memory>
namespace boost { namespace python { namespace indexing {
struct python_iterator
{
virtual ~python_iterator ();
virtual bool next () = 0;
virtual boost::python::object current() const = 0;
};
std::auto_ptr<python_iterator> make_iterator (boost::python::object);
// Returns null auto_ptr if object does not provide __iter__ nor
// __getitem__, otherwise a pointer to a suitable implementation of
// python_iterator
struct python_getitem_iterator : public python_iterator
{
public:
python_getitem_iterator (boost::python::object);
virtual bool next ();
virtual boost::python::object current() const;
private:
boost::python::object mGetitemMethod;
int mIndex;
boost::python::object mCurrent;
};
struct python_iter_iterator : public python_iterator
{
public:
python_iter_iterator (boost::python::object);
virtual bool next ();
virtual boost::python::object current() const;
private:
boost::python::object mNextMethod;
boost::python::object mCurrent;
};
} } }
#endif // python_iterator_rmg_20030910_included

View File

@@ -0,0 +1,101 @@
// -*- mode:c++; switch-modules-target: "container_proxy.hpp" -*-
//
// Header file shared_proxy_impl.hpp
//
// The shared implementation of the element proxy (const and non-const
// versions). Multiple proxy pointers can refer to the same shared
// implementation, meaning that only one object requires updating to
// affect all proxy pointers that ultimately refer to the same index
// in the container.
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 8/29 rmg File creation from container_proxy.hh
//
// $Id$
//
#ifndef shared_proxy_impl_rmg_20030829_included
#define shared_proxy_impl_rmg_20030829_included
#include <memory>
namespace boost { namespace python { namespace indexing {
template<class ContainerProxy>
class shared_proxy_impl
{
public:
typedef typename ContainerProxy::raw_value_type value_type;
typedef value_type &reference;
typedef value_type *pointer;
typedef void iterator_category; // Fudge for boost::indirect_iterator
typedef void difference_type; // Fudge for boost::indirect_iterator
reference operator*() const;
pointer operator->() const { return &(**this); }
ContainerProxy *owner() const { return myOwnerPtr; }
size_t index() const { return myIndex; }
shared_proxy_impl (value_type const &copy);
// Creates value-only (detached) proxy
private:
template<class C, class A> friend class container_proxy;
shared_proxy_impl (ContainerProxy *, size_t);
void detach ();
private:
ContainerProxy *myOwnerPtr; // When attached
size_t myIndex; // When attached
std::auto_ptr<value_type> myElementPtr; // When detached
private:
// Not implemented
shared_proxy_impl (shared_proxy_impl const &);
shared_proxy_impl &operator= (shared_proxy_impl const &);
};
template<class ContainerProxy>
shared_proxy_impl<ContainerProxy>::shared_proxy_impl (ContainerProxy *ownerPtr
, size_t index)
: myOwnerPtr (ownerPtr)
, myIndex (index)
, myElementPtr ()
{
}
template<class ContainerProxy>
shared_proxy_impl<ContainerProxy>::shared_proxy_impl (value_type const &val)
: myOwnerPtr (0)
, myIndex (-1)
, myElementPtr (new value_type (val))
{
}
template<class ContainerProxy>
typename shared_proxy_impl<ContainerProxy>::reference
shared_proxy_impl<ContainerProxy>::operator* () const
{
return myOwnerPtr
? myOwnerPtr->raw_container().at (myIndex)
: *myElementPtr;
}
template<class ContainerProxy>
void shared_proxy_impl<ContainerProxy>::detach ()
{
myElementPtr.reset (new value_type (**this));
myOwnerPtr = 0;
myIndex = static_cast<size_t>(-1);
}
} } }
#endif // shared_proxy_impl_rmg_20030829_included

View File

@@ -0,0 +1,83 @@
// -*- mode:c++ -*-
//
// Header file slice.hpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 9/10 rmg File creation
//
// $Id$
//
#ifndef slice_rmg_20030910_included
#define slice_rmg_20030910_included
#include <boost/python/object.hpp>
#include <boost/python/converter/pytype_object_mgr_traits.hpp>
namespace boost { namespace python { namespace indexing {
struct slice : public boost::python::object
{
//
// *** WARNING ***
//
// A newly constructed slice object is useless until setLength is called
//
template<typename T> slice (T const &ref);
void setLength (int sequenceLength);
int start() const { validate(); return mStart; }
int step() const { validate(); return mStep; }
int stop() const { validate(); return mStop; }
int size() const { validate(); return (mStop - mStart) / mStep; }
bool inRange (int index);
private:
void validate () const; // throws unless setLength has been called
int mStart;
int mStep;
int mStop;
int mDirection;
};
} } }
template<typename T>
boost::python::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<>
struct object_manager_traits<boost::python::indexing::slice>
: pytype_object_manager_traits<&PySlice_Type, ::boost::python::indexing::slice>
{
};
}}}
#endif // slice_rmg_20030910_included

View File

@@ -0,0 +1,395 @@
// -*- mode:c++ -*-
//
// Header file slice_handler.hpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 9/ 9 rmg File creation
//
// $Id$
//
#ifndef slice_handler_rmg_20030909_included
#define slice_handler_rmg_20030909_included
#include <boost/python/object.hpp>
#include <boost/python/list.hpp>
#include <boost/python/extract.hpp>
#include <boost/mpl/apply.hpp>
#include <algorithm>
#include <boost/python/suite/indexing/slice.hpp>
#include <boost/python/suite/indexing/python_iterator.hpp>
namespace boost { namespace python { namespace indexing {
template<class Algorithms, class Policy>
struct slice_handler
{
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;
typedef typename Algorithms::reference reference;
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
{
// This class overrides our Policy's postcall function and
// result_conveter to handle the list returned from get_slice.
// The Policy's result_converter is removed, since it gets
// applied within get_slice. Our postcall override applies the
// original postcall to each element of the Python list returned
// from get_slice.
typedef boost::python::default_result_converter result_converter;
typedef typename Policy::argument_package argument_package; // ?
postcall_override (Policy const &p);
bool precall (PyObject *args);
PyObject* postcall (PyObject *args, PyObject *result);
private:
Policy mBase;
};
};
template<bool doit> struct maybe_insert {
template<class Algorithms>
static void apply (typename Algorithms::container &
, typename Algorithms::index_param
, typename Algorithms::value_param)
{
PyErr_SetString (PyExc_TypeError
, "container does not support item insertion");
boost::python::throw_error_already_set ();
}
};
template<> struct maybe_insert<true> {
template<class Algorithms>
static void apply (typename Algorithms::container &c
, typename Algorithms::index_param i
, typename Algorithms::value_param v)
{
Algorithms::insert (c, i, v);
}
};
template<bool doit> struct maybe_erase {
template<class Algorithms>
static void apply (typename Algorithms::container &
, typename Algorithms::index_param
, typename Algorithms::index_param)
{
PyErr_SetString (PyExc_TypeError
, "container does not support item deletion");
boost::python::throw_error_already_set ();
}
};
template<> struct maybe_erase<true> {
template<class Algorithms>
static void apply (typename Algorithms::container &c
, typename Algorithms::index_param from
, typename Algorithms::index_param to)
{
Algorithms::erase_range (c, from, to);
}
};
//////////////////////////////////////////////////////////////////////////
// postcall_override constructor
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
slice_handler<Algorithms, Policy>
::postcall_override::postcall_override (Policy const &p)
: mBase (p)
{
}
//////////////////////////////////////////////////////////////////////////
// precall forwarder
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
bool
slice_handler<Algorithms, Policy>
::postcall_override::precall (PyObject *args)
{
return mBase.precall (args);
}
//////////////////////////////////////////////////////////////////////////
// Apply base postcall to each element of the list returend by get_slice
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
PyObject *
slice_handler<Algorithms, Policy>
::postcall_override::postcall (PyObject *args, PyObject *result)
{
int size = PyList_Size (result);
for (int count = 0; count < size; ++count)
{
mBase.postcall (args, PyList_GetItem (result, count));
}
return result;
}
//////////////////////////////////////////////////////////////////////////
// Return a function object that implements the slice version of __getitem__
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
boost::python::object
slice_handler<Algorithms, Policy>
::make_getitem (Policy const &policy)
{
return
boost::python::make_function (get_slice, postcall_override (policy));
}
//////////////////////////////////////////////////////////////////////////
// Return a function object that implements the slice version of __setitem__
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
boost::python::object
slice_handler<Algorithms, Policy>
::make_setitem (Policy const &policy)
{
// should we try to get funky with policy::precall?
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
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
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__
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
boost::python::list
slice_handler<Algorithms, Policy>
::get_slice (container &c, slice sl)
{
typedef typename Policy::result_converter converter_type;
typedef typename Algorithms::reference reference;
typename boost::mpl::apply1<converter_type, reference>::type converter;
boost::python::list result;
sl.setLength (Algorithms::size(c));
for (int index = sl.start(); sl.inRange (index); index += sl.step())
{
// Apply the result converter (only) to each element before
// appending. postcall is done in postcall_override
result.append
(boost::python::handle<>
(converter (Algorithms::get (c, index))));
}
return result;
}
//////////////////////////////////////////////////////////////////////////
// Implementation for the slice version of __setitem__
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
void
slice_handler<Algorithms, Policy>
::set_slice (container &c, slice sl, boost::python::object values)
{
std::auto_ptr<python_iterator> iterPtr (make_iterator (values));
if (!iterPtr.get())
{
PyErr_SetString (PyExc_TypeError
, "Type assigned to slice must be a sequence");
boost::python::throw_error_already_set();
}
typedef typename Algorithms::container_traits traits;
// 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
// replacement sequence is of a different length to the original
// slice and the container does not support insertion/deletion.
// This could be prevented if the length of the replacement sequence
// is known in advance (via __len__, for example) but not otherwise.
sl.setLength (Algorithms::size (c)); // Current length of our container
int index = sl.start(); // Index in our container for update
// Overwrite and/or insert elements
while (iterPtr->next())
{
if (sl.inRange (index))
{
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)
{
PyErr_SetString (PyExc_ValueError
, "attempt to insert via extended slice");
boost::python::throw_error_already_set ();
}
else
{
// Could optimize this in some cases (i.e. if the length of
// the replacement sequence is known)
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();
}
// Erase any remaining elements in the slice
if (sl.inRange(index))
{
if (sl.step() != 1)
{
PyErr_SetString (PyExc_ValueError
, "attempt to erase via extended slice");
boost::python::throw_error_already_set ();
}
else
{
maybe_erase<traits::has_erase>
::template apply<Algorithms> (c, index, sl.stop());
}
}
}
//////////////////////////////////////////////////////////////////////////
// Implementation for the slice version of __delitem__
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
void
slice_handler<Algorithms, Policy>
::del_slice (container &c, slice sl)
{
typename Algorithms::size_type length (Algorithms::size (c));
// avoid bounds check problems with deleting [0..0) when length==0
if (length)
{
sl.setLength (length);
Algorithms::erase_range (c, sl.start(), sl.stop());
}
}
//////////////////////////////////////////////////////////////////////////
// Implementation of extend
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
void
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)))));
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

@@ -0,0 +1,75 @@
// -*- mode:c++ -*-
//
// Header file suite_utils.hpp
//
// Shared utilities for the indexing suite.
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 8/23 rmg File creation
//
// $Id$
//
#ifndef suite_utils_rmg_20030823_included
#define suite_utils_rmg_20030823_included
#include <boost/type_traits.hpp>
namespace boost { namespace python { namespace indexing {
template<typename T>
class is_mutable_ref
{
typedef typename boost::remove_reference<T>::type maybe_const;
public:
static bool const value = ! boost::is_const<maybe_const>::value;
};
// make_signed attempts to identify the signed version of any
// numeric type (useful in this case because Python container
// indexes can be negative).
template<typename T> struct make_signed {
typedef T type;
};
template<> struct make_signed<char> {
// Raw "char" could be signed or unsigned. "signed char"
// guarantess signedness
typedef signed char type;
};
template<> struct make_signed<unsigned char> {
typedef signed char type;
};
template<> struct make_signed<unsigned short> {
typedef short type;
};
template<> struct make_signed<unsigned int> {
typedef int type;
};
template<> struct make_signed<unsigned long> {
typedef long type;
};
#if defined (BOOST_HAS_LONG_LONG)
template<> struct make_signed<unsigned long long> {
typedef long long type;
};
#elif defined (BOOST_HAS_MS_INT64)
template<> struct make_signed<unsigned __int64> {
typedef __int64 type;
};
#endif
} } }
#endif // suite_utils_rmg_20030823_included

View File

@@ -0,0 +1,41 @@
// -*- mode:c++ -*-
//
// Header file value_traits.hpp
//
// Traits information about container element types for use in
// determining which Python methods to support for a container.
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 9/12 rmg File creation
//
// $Id$
//
#ifndef value_traits_rmg_20030912_included
#define value_traits_rmg_20030912_included
namespace boost { namespace python { namespace indexing {
template<typename T>
struct value_traits {
static bool const equality_comparable = true;
// Meaning from C++98 standard section 20.1.1
static bool const lessthan_comparable = true;
// static bool const has_less = true;
// etc...
// Default, do-nothing, version of visitor_helper
template<typename PythonClass, typename Policy>
static void visitor_helper (PythonClass &, Policy const &) { }
};
} } }
#endif // value_traits_rmg_20030912_included

View File

@@ -0,0 +1,520 @@
// -*- mode:c++ -*-
//
// Header file visitor.hpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// History
// =======
// 2003/ 9/11 rmg File creation from container_suite.hpp
//
// $Id$
//
#ifndef visitor_rmg_20030823_included
#define visitor_rmg_20030823_included
#include <boost/python/suite/indexing/slice_handler.hpp>
#include <boost/python/def_visitor.hpp>
#include <boost/python/iterator.hpp>
#include <boost/bind.hpp>
#include <functional>
namespace boost { namespace python { 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>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("__getitem__", &Algorithms::get, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// __getitem__ with slice
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_getitem<index_style_linear> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("__getitem__", &Algorithms::get, policy);
pyClass.def ("__getitem__"
, slice_handler<Algorithms, Policy>::make_getitem (policy));
}
};
//////////////////////////////////////////////////////////////////////////
// __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>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("__setitem__", &Algorithms::assign, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// __setitem__ with slice
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_setitem<index_style_linear> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("__setitem__", &Algorithms::assign, policy);
pyClass.def ("__setitem__"
, slice_handler<Algorithms, Policy>::make_setitem (policy));
}
};
//////////////////////////////////////////////////////////////////////////
// __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>
static void apply (PythonClass &pyClass
, 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));
}
};
//////////////////////////////////////////////////////////////////////////
// sort dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit, bool lessthan_comparable>
struct maybe_add_sort {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// sort real
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_sort<true, true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("sort", &Algorithms::sort, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// reverse dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit>
struct maybe_add_reverse {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// reverse real
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_reverse<true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("reverse", &Algorithms::reverse, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// 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>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("append", &Algorithms::push_back, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// extend dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit>
struct maybe_add_insert {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
//////////////////////////////////////////////////////////////////////////
// insert real
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_insert<true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
pyClass.def ("insert", Algorithms::insert, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// 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
//////////////////////////////////////////////////////////////////////////
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", Algorithms::get_index, 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);
pyClass.def ("contains", Algorithms::contains, 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);
pyClass.def ("__contains__", Algorithms::contains, policy);
}
};
//////////////////////////////////////////////////////////////////////////
// count real (associative containers). add has_key
//////////////////////////////////////////////////////////////////////////
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", Algorithms::contains, policy);
pyClass.def ("__contains__", Algorithms::contains, 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 > >
{
Policy mPolicy;
public:
typedef Algorithms algorithms;
typedef typename algorithms::container_traits traits;
typedef typename traits::value_traits_ value_traits_;
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_sort<traits::is_reorderable
, value_traits_::lessthan_comparable>
::apply (pyClass, algorithms(), precallPolicy);
maybe_add_reverse<traits::is_reorderable>
::apply (pyClass, algorithms(), precallPolicy);
maybe_add_append<traits::has_push_back>
::apply (pyClass, algorithms(), precallPolicy);
maybe_add_insert<traits::has_insert>
::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);
}
};
} } }
#endif // visitor_rmg_20030823_included