2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-26 06:42:27 +00:00

Extract traits into separate header, started implementation of suite

[SVN r1509]
This commit is contained in:
Raoul Gough
2003-09-09 18:23:45 +00:00
parent eec4ec6701
commit 74e16eb651

View File

@@ -17,6 +17,7 @@
// History
// =======
// 2003/ 8/23 rmg File creation
// 2003/ 9/ 8 rmg Extracted trait facilities into container_traits.hpp
//
// $Id$
//
@@ -24,325 +25,138 @@
#ifndef container_suite_rmg_20030823_included
#define container_suite_rmg_20030823_included
#include "suite_utils.hpp"
#include "iterator_suite.hpp"
#include <boost/type_traits.hpp>
#include "container_traits.hpp"
#include "slice_handler.hpp"
#include <set>
#include <map>
#include <list>
#include <deque>
#include <vector>
#include <boost/python/return_by_value.hpp>
#include <boost/python/return_value_policy.hpp>
#include <boost/python/def_visitor.hpp>
#include <boost/python/iterator.hpp>
// #include <boost/python/return_internal_reference.hpp>
namespace indexing {
//////////////////////////////////////////////////////////////////////////
// Iterator pair container emulation
//////////////////////////////////////////////////////////////////////////
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;
private:
iterator myBegin;
iterator myEnd;
template<IndexStyle>
struct maybe_add_getitem {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
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
{
return *(begin() + index);
}
/////////////////////////////////////////////////////////////////////////
// Container traits
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
// Traits for the iterator_pair container emulator
/////////////////////////////////////////////////////////////////////////
template<typename IteratorPair>
struct iterator_pair_traits
: public
iterator_detail::traits_by_category<typename IteratorPair::iterator>::type
{
typedef IteratorPair container;
typedef typename IteratorPair::size_type size_type;
typedef typename IteratorPair::size_type index_type; // at()
static bool const has_insert = false;
static bool const has_erase = false;
static bool const has_pop_back = false;
static bool const has_push_back = false;
// Default implementations of support functions
typedef container_algorithms<iterator_pair_traits> algorithms;
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);
}
};
/////////////////////////////////////////////////////////////////////////
// Lowest common denominator (almost all "real" containers would
// meet at least these requirements)
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct default_container_traits
{
protected:
static bool const is_mutable = ! boost::is_const<Container>::value;
public:
typedef Container container;
typedef typename Container::value_type value_type;
typedef typename Container::reference reference;
typedef typename Container::difference_type difference_type;
typedef typename Container::size_type size_type;
typedef typename Container::size_type index_type; // at()
typedef value_type key_type; // find, count, ...
// Should probably select iterator or const_iterator on the
// basis of is_mutable
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
static bool const has_copyable_iter = true;
static bool const has_random_access
= ::indexing::iterator_traits<iterator>::has_random_access;
static bool const has_mutable_ref
= is_mutable && is_mutable_ref<reference>::value;
// has_mutable_ref basically means that the container supports
// in-place replacement of values (e.g. the associative containers
// *don't*)
static bool const is_reversible = has_mutable_ref;
static bool const has_insert = is_mutable;
static bool const has_erase = is_mutable;
static bool const has_pop_back = false;
static bool const has_push_back = false;
// Default implementations of support functions
typedef container_algorithms<default_container_traits> algorithms;
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__"
, slice_handler<Algorithms, Policy>::make_getitem (policy));
}
};
/////////////////////////////////////////////////////////////////////////
// Sequences (list, deque, vector)
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct default_sequence_traits : public default_container_traits<Container>
{
static bool const has_pop_back = is_mutable;
static bool const has_push_back = is_mutable;
template<IndexStyle>
struct maybe_add_setitem {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
template<typename Container>
struct list_traits : public default_sequence_traits<Container>
{
// Some special algo's for list (using member functions)
typedef list_algorithms<list_traits> algorithms;
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);
}
};
/////////////////////////////////////////////////////////////////////////
// Associative containers set and multiset
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct set_traits : public default_container_traits<Container>
{
// Special algo's for set types (using member functions)
typedef assoc_algorithms<set_traits> algorithms;
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);
// *FIXME* add slicing support
}
};
/////////////////////////////////////////////////////////////////////////
// Associative containers map and multimap
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct map_traits : public default_container_traits<Container>
{
typedef typename Container::key_type key_type; // find, count, ...
// Special algo's for map types (using member functions)
typedef assoc_algorithms<map_traits> algorithms;
template<bool doit>
struct maybe_add_iter {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
/////////////////////////////////////////////////////////////////////////
// Automated trait selection
/////////////////////////////////////////////////////////////////////////
namespace container_details {
template<typename Container> struct traits_by_type;
// traits_by_type instances should include two typedefs, one for
// the non-const version of the container, and one for the
// const version. This saves having to have two specializations
// of traits_by_type for every kind of container.
// std::set
template <class Key, class Compare, class Allocator>
class traits_by_type<std::set<Key, Compare, Allocator> >
template<>
struct maybe_add_iter<true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &pyClass
, Algorithms const &
, Policy const &policy)
{
typedef std::set<Key, Compare, Allocator> Container;
public:
typedef set_traits<Container> mutable_type;
typedef set_traits<Container const> const_type;
};
// std::multiset
template <class Key, class Compare, class Allocator>
class traits_by_type<std::multiset<Key, Compare, Allocator> >
{
typedef std::multiset<Key, Compare, Allocator> Container;
public:
typedef set_traits<Container> mutable_type;
typedef set_traits<Container const> const_type;
};
// std::map
template <class Key, class T, class Compare, class Allocator>
class traits_by_type<std::map<Key, T, Compare, Allocator> >
{
typedef std::map<Key, T, Compare, Allocator> Container;
public:
typedef map_traits<Container> mutable_type;
typedef map_traits<Container const> const_type;
};
// std::multimap
template <class Key, class T, class Compare, class Allocator>
class traits_by_type<std::multimap<Key, T, Compare, Allocator> >
{
typedef std::multimap<Key, T, Compare, Allocator> Container;
public:
typedef map_traits<Container> mutable_type;
typedef map_traits<Container const> const_type;
};
// std::vector
template <class T, class Allocator>
class traits_by_type<std::vector<T, Allocator> >
{
typedef std::vector<T, Allocator> Container;
public:
typedef default_sequence_traits<Container> mutable_type;
typedef default_sequence_traits<Container const> const_type;
};
// std::deque
template <class T, class Allocator>
class traits_by_type<std::deque<T, Allocator> >
{
typedef std::deque<T, Allocator> Container;
public:
typedef default_sequence_traits<Container> mutable_type;
typedef default_sequence_traits<Container const> const_type;
};
// std::list
template <class T, class Allocator>
class traits_by_type<std::list<T, Allocator> >
{
typedef std::list<T, Allocator> Container;
public:
typedef list_traits<Container> mutable_type;
typedef list_traits<Container const> const_type;
};
// Iterator ranges
template <typename Iterator>
class traits_by_type<indexing::iterator_pair<Iterator> >
{
typedef ::indexing::iterator_pair<Iterator> Container;
public:
typedef iterator_pair_traits<Container> mutable_type;
typedef iterator_pair_traits<Container const> const_type; // ?
};
}
// Select the right traits for each supported kind of container
// Generic version (mutable containers)
template<class Container>
struct container_traits
: public container_details::traits_by_type<Container>::mutable_type
{
pyClass.def ("__iter__"
, boost::python::range<Policy> (Algorithms::begin
, Algorithms::end));
}
};
// Partial specialization for const containers
template<class Container>
struct container_traits<Container const>
: public container_details::traits_by_type<Container>::const_type
template<bool doit>
struct maybe_add_append {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
};
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);
}
};
template<class Container
, class Traits = container_traits<Container> >
struct container_suite
: public boost::python::def_visitor<container_suite<Container, Traits> >
{
typedef typename Traits::algorithms algorithms;
typedef typename Traits::reference reference_return;
typedef boost::python::return_value_policy<boost::python::return_by_value>
return_policy;
template <class PythonClass>
static void visit (PythonClass &pyClass)
{
maybe_add_getitem<Traits::index_style>
::apply (pyClass, algorithms(), return_policy());
maybe_add_setitem<Traits::index_style>
::apply (pyClass, algorithms(), return_policy());
maybe_add_iter<((Traits::index_style != index_style_linear)
&& Traits::has_copyable_iter)>
::apply (pyClass, algorithms(), return_policy());
maybe_add_append<Traits::has_push_back>
::apply (pyClass, algorithms(), return_policy());
}
};
}