diff --git a/include/boost/python/suite/indexing/algo_selector.hpp b/include/boost/python/suite/indexing/algo_selector.hpp new file mode 100755 index 00000000..63a425bf --- /dev/null +++ b/include/boost/python/suite/indexing/algo_selector.hpp @@ -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 +#include + +// Definitions of supported types +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { namespace indexing { + ///////////////////////////////////////////////////////////////////////// + // Automated algorithm and trait selection + ///////////////////////////////////////////////////////////////////////// + + namespace detail { + template 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 selector_impl > + { + typedef std::set Container; + + typedef set_traits mutable_traits; + typedef set_traits const_traits; + + public: + typedef set_algorithms mutable_algorithms; + typedef set_algorithms const_algorithms; + }; + + // std::multiset + template + class selector_impl > + { + typedef std::multiset Container; + + typedef set_traits mutable_traits; + typedef set_traits const_traits; + + public: + typedef set_algorithms mutable_algorithms; + typedef set_algorithms const_algorithms; + }; + + // std::map + template + class selector_impl > + { + typedef std::map Container; + + typedef map_traits mutable_traits; + typedef map_traits const_traits; + + public: + typedef map_algorithms mutable_algorithms; + typedef map_algorithms const_algorithms; + }; + + // std::multimap + template + class selector_impl > + { + typedef std::multimap Container; + + typedef map_traits mutable_traits; + typedef map_traits const_traits; + + public: + typedef map_algorithms mutable_algorithms; + typedef map_algorithms const_algorithms; + }; + + // std::vector + template + class selector_impl > + { + typedef std::vector Container; + + typedef default_sequence_traits mutable_traits; + typedef default_sequence_traits const_traits; + + public: + typedef default_algorithms mutable_algorithms; + typedef default_algorithms const_algorithms; + }; + + // std::deque + template + class selector_impl > + { + typedef std::deque Container; + + typedef default_sequence_traits mutable_traits; + typedef default_sequence_traits const_traits; + + public: + typedef default_algorithms mutable_algorithms; + typedef default_algorithms const_algorithms; + }; + + // std::list + template + class selector_impl > + { + typedef std::list Container; + + typedef default_sequence_traits mutable_traits; + typedef default_sequence_traits const_traits; + + public: + typedef list_algorithms mutable_algorithms; + typedef list_algorithms const_algorithms; + }; + + // Iterator ranges + template + class selector_impl > + { + typedef iterator_pair Container; + + typedef iterator_pair_traits mutable_traits; + typedef iterator_pair_traits const_traits; // ? + + public: + typedef default_algorithms mutable_algorithms; + typedef default_algorithms const_algorithms; + }; + + // Container proxies + template + class selector_impl > + { + typedef container_proxy Container; + + typedef container_proxy_traits mutable_traits; + typedef container_proxy_traits const_traits; + + public: + typedef default_algorithms mutable_algorithms; + typedef default_algorithms const_algorithms; + }; + } + + // Select the right algorithms for each supported kind of container + + // Generic version (mutable containers) + template + struct algo_selector + : public detail::selector_impl::mutable_algorithms + { + }; + + // Partial specialization for const containers + template + struct algo_selector + : public detail::selector_impl::const_algorithms + { + }; +} } } + +#endif // algo_selector_rmg_20030911_included diff --git a/include/boost/python/suite/indexing/algorithms.hpp b/include/boost/python/suite/indexing/algorithms.hpp new file mode 100755 index 00000000..803200a4 --- /dev/null +++ b/include/boost/python/suite/indexing/algorithms.hpp @@ -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 + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { namespace indexing { + template + 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 + 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 + struct list_algorithms : public default_algorithms + { + private: + typedef default_algorithms 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 + struct assoc_algorithms : public default_algorithms + { + private: + typedef default_algorithms 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 + struct set_algorithms : public assoc_algorithms + { + private: + typedef assoc_algorithms 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 + struct map_algorithms : public assoc_algorithms + { + private: + typedef assoc_algorithms 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 default_algorithms::size_type + default_algorithms::size (container &c) + { + return c.size(); + } + + ///////////////////////////////////////////////////////////////////////// + // Range check an index and throw out_of_range if necessary + ///////////////////////////////////////////////////////////////////////// + + template + typename default_algorithms::size_type + default_algorithms::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 default_algorithms::iterator + default_algorithms::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 default_algorithms::size_type + default_algorithms::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 default_algorithms::size_type + default_algorithms::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 + bool + default_algorithms::contains (container &c + , key_param key) + { + return find (c, key) != end(c); + } + + ///////////////////////////////////////////////////////////////////////// + // Index into a container (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + typename default_algorithms::reference + default_algorithms::get (container &c + , index_param ix) + { + return c[bounds_check (c, ix, "get")]; + } + + ///////////////////////////////////////////////////////////////////////// + // Assign a value at a particular index (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + void + default_algorithms::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 + void + default_algorithms::push_back (container &c + , value_param v) + { + c.push_back (v); + } + + ///////////////////////////////////////////////////////////////////////// + // Insert at an index in the container (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + void + default_algorithms::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 + void + default_algorithms::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 + void + default_algorithms::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 + void default_algorithms::reverse (container &c) + { + std::reverse (begin(c), end(c)); + } + + ///////////////////////////////////////////////////////////////////////// + // Sort the contents of a container (std algorithm version) + ///////////////////////////////////////////////////////////////////////// + + template + void default_algorithms::sort (container &c) + { + std::sort (begin(c), end(c)); + } + + ///////////////////////////////////////////////////////////////////////// + // Visitor helper function (default version) + ///////////////////////////////////////////////////////////////////////// + + template + template + void + default_algorithms + ::visitor_helper (PythonClass &pyClass, Policy const &policy) + { + container_traits::visitor_helper (pyClass, policy); + } + + ///////////////////////////////////////////////////////////////////////// + // Reverse the contents of a list (member function version) + ///////////////////////////////////////////////////////////////////////// + + template + void list_algorithms::reverse (container &c) + { + c.reverse(); + } + + ///////////////////////////////////////////////////////////////////////// + // Sort the contents of a container (std algorithm version) + ///////////////////////////////////////////////////////////////////////// + + template + void list_algorithms::sort (container &c) + { + c.sort(); + } + + ///////////////////////////////////////////////////////////////////////// + // Index into a container (associative version) + ///////////////////////////////////////////////////////////////////////// + + template + typename assoc_algorithms::reference + assoc_algorithms::get (container &c, index_param ix) + { + return *find_or_throw (c, ix); + } + + ///////////////////////////////////////////////////////////////////////// + // Index into a container (map version) + ///////////////////////////////////////////////////////////////////////// + + template + typename map_algorithms::reference + map_algorithms::get (container &c, index_param ix) + { + return find_or_throw (c, ix)->second; + } + + ///////////////////////////////////////////////////////////////////////// + // Erase elements with the given key (associative version) + ///////////////////////////////////////////////////////////////////////// + + template + void + assoc_algorithms::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 + void + set_algorithms::assign (container &c + , index_param ix + , value_param val) + { + insert (c, ix); // Ignore dummy value parameter + } + + ///////////////////////////////////////////////////////////////////////// + // Insert an element into a set + ///////////////////////////////////////////////////////////////////////// + + template + void + set_algorithms::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 + void + map_algorithms::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 + void + map_algorithms::insert (container &c + , index_param ix + , value_param val) + { + typedef std::pair + + 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 assoc_algorithms::iterator + assoc_algorithms::find (container &c, key_param key) + { + return c.find (key); + } + + ///////////////////////////////////////////////////////////////////////// + // Find an element in an associative container + ///////////////////////////////////////////////////////////////////////// + + template + bool + assoc_algorithms::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 assoc_algorithms::iterator + assoc_algorithms::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 assoc_algorithms::size_type + assoc_algorithms::count (container &c + , key_param key) + { + return c.count (key); + } +} } } + +#endif // algorithms_rmg_20030823_included diff --git a/include/boost/python/suite/indexing/container_proxy.hpp b/include/boost/python/suite/indexing/container_proxy.hpp new file mode 100755 index 00000000..b5753d14 --- /dev/null +++ b/include/boost/python/suite/indexing/container_proxy.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { namespace indexing { + template 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 ©) { return copy; } + static void assign (T &to, T const &from) { to = from; } + static void pre_destruction (T &) { } + }; + + template struct deref { + typedef P held_type; + + typedef typename boost::iterator_value

::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 ©) { return copy; } + static void assign (P &to, P const &from) { to = from; } + static void pre_destruction (P &) { } + }; + + template > + class container_proxy + { + typedef container_proxy self_type; + typedef typename Container::iterator raw_iterator; + typedef std::iterator_traits raw_iterator_traits; + + template 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 shared_proxy; + + typedef typename Container::value_type raw_value_type; + + typedef element_proxy value_type; + typedef value_type reference; // Already has ref. semantics + + typedef const_element_proxy 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 ©) { 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 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 void insert (iterator, Iter, Iter); + + void push_back (raw_value_type const ©) { 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 void replace (size_type index, Iter, Iter); + + private: + // Overloads for insertions with/without useful std::distance + template + void insert (iterator, Iter, Iter, std::forward_iterator_tag); + + template + void insert (iterator, Iter, Iter, std::input_iterator_tag); + + private: + typedef boost::shared_ptr pointer_impl; + typedef std::map 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 + void adjustIndexes (Iter, Iter, long offset); + + void erase_helper (MapIterator); + void erase_helper (ReverseIterator); + + private: + held_type myHeldObj; + MapType myMap; + }; + + template + container_proxy + ::container_proxy () + : myHeldObj () + , myMap () + { + } + + template + container_proxy + ::container_proxy (held_type const &heldType) + : myHeldObj (heldType) + , myMap () + { + } + + template + template + container_proxy + ::container_proxy (Iter start, Iter finish) + : myHeldObj (Holder::create()) + , myMap () + { + insert (begin(), start, finish); + } + + template + container_proxy + ::container_proxy (container_proxy const ©) + : myHeldObj (Holder::copy (copy.myHeldObj)) + , myMap () // Do *not* duplicate map + { + } + + template + container_proxy & + container_proxy + ::operator= (container_proxy const ©) + { + // 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 + container_proxy + ::~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 + Container & + container_proxy + ::raw_container () + { + return Holder::get (myHeldObj); + } + + template + Container const & + container_proxy + ::raw_container () const + { + return Holder::get (myHeldObj); + } + + template + typename container_proxy::reference + container_proxy + ::at (size_type index) + { + pointer_impl &entry = myMap[index]; + + if (!entry.get()) + { + entry.reset (new shared_proxy (this, index)); + } + + return reference (entry); + } + + template + typename container_proxy::const_reference + container_proxy + ::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(this); + + return const_reference (mutable_this->at (index)); + } + + template + void + container_proxy + ::replace (size_type index, raw_value_type const ©) + { + detach_proxy (index); + raw_container().at(index) = copy; + } + + template + template + void + container_proxy + ::replace (size_type index, Iter from, Iter to) + { + while (from != to) + { + replace (index++, *from++); + } + } + + template + typename container_proxy::iterator + container_proxy + ::erase (iterator iter) + { + return erase (iter, iter + 1); + } + + template + typename container_proxy::iterator + container_proxy + ::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 + typename container_proxy::iterator + container_proxy + ::insert (iterator iter, raw_value_type const ©) + { + 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 + template + void + container_proxy + ::insert (iterator iter, Iter from, Iter to) + { + // Forward insertion to the right overloaded version + typedef typename std::iterator_traits::iterator_category category; + insert (iter, from, to, category()); + } + + template + template + void + container_proxy + ::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 + template + void + container_proxy + ::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 + void + container_proxy + ::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 + void + container_proxy + ::detach_proxy (size_type index) + { + MapIterator iter = myMap.find (index); + + if (iter != myMap.end()) + { + detach_if_shared (*iter); + myMap.erase (iter); + } + } + + template + void + container_proxy + ::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 + void + container_proxy + ::detach_proxies (iterator from, iterator to) + { + assert (from.ptr == this); + assert (to.ptr == this); + detach_proxies (from.index, to.index); + } + + template + template + void + container_proxy + ::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 + void + container_proxy + ::erase_helper (MapIterator iter) + { + myMap.erase (iter); + } + + template + void + container_proxy + ::erase_helper (ReverseIterator iter) + { + ++iter; + myMap.erase (iter.base()); + } +} } } + +#endif // container_proxy_rmg_20030826_included diff --git a/include/boost/python/suite/indexing/container_suite.hpp b/include/boost/python/suite/indexing/container_suite.hpp new file mode 100755 index 00000000..5c3fab36 --- /dev/null +++ b/include/boost/python/suite/indexing/container_suite.hpp @@ -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 +#include + +#include +#include + +namespace boost { namespace python { namespace indexing { + typedef boost::python::return_value_policy + default_container_policies; + + template > + struct container_suite + : public visitor + { + typedef Algorithms algorithms; + + template + static visitor with_policies (Policy const &policy) + { + return visitor (policy); + } + }; +} } } + +#endif // container_suite_rmg_20030823_included diff --git a/include/boost/python/suite/indexing/container_traits.hpp b/include/boost/python/suite/indexing/container_traits.hpp new file mode 100755 index 00000000..a2763f0b --- /dev/null +++ b/include/boost/python/suite/indexing/container_traits.hpp @@ -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 +#include +#include + +#include +#include + +namespace boost { namespace python { namespace indexing { + ///////////////////////////////////////////////////////////////////////// + // Lowest common denominator traits - applicable to real containers + // and iterator pairs + ///////////////////////////////////////////////////////////////////////// + + template + struct base_container_traits + : public iterator_detail::traits_by_category + ::type + { + protected: + typedef typename + iterator_detail::traits_by_category + ::type base_type; + + BOOST_STATIC_CONSTANT (bool, is_mutable + = ! boost::is_const::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::type index_type; + // at(), operator[]. Signed to support Python -ve indexes + + typedef typename boost::call_traits::param_type value_param; + typedef typename boost::call_traits::param_type key_param; + typedef typename boost::call_traits::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 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 + static void visitor_helper (PythonClass &, Policy const &); + }; + + ///////////////////////////////////////////////////////////////////////// + // Traits for the iterator_pair container emulator + ///////////////////////////////////////////////////////////////////////// + + template + struct iterator_pair_traits : public base_container_traits + { + }; + + ///////////////////////////////////////////////////////////////////////// + // Default container traits - almost all "real" containers would meet + // at least these requirements + ///////////////////////////////////////////////////////////////////////// + + template + struct default_container_traits : public base_container_traits + { + BOOST_STATIC_CONSTANT (bool, has_insert = is_mutable); + BOOST_STATIC_CONSTANT (bool, has_erase = is_mutable); + }; + + ///////////////////////////////////////////////////////////////////////// + // Sequences (list, deque, vector) + ///////////////////////////////////////////////////////////////////////// + + template + struct default_sequence_traits : public default_container_traits + { + BOOST_STATIC_CONSTANT (bool, has_pop_back = is_mutable); + BOOST_STATIC_CONSTANT (bool, has_push_back = is_mutable); + }; + + ///////////////////////////////////////////////////////////////////////// + // Sequences within a container_proxy + ///////////////////////////////////////////////////////////////////////// + + template + struct container_proxy_traits : public default_sequence_traits + { + 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::param_type value_param; + typedef typename boost::call_traits::param_type key_param; + + typedef value_traits 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 + struct set_traits : public default_container_traits + { + // *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::param_type key_param; + typedef typename boost::call_traits::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 + struct map_traits : public default_container_traits + { + // *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::param_type value_param; + typedef typename boost::call_traits::param_type key_param; + typedef typename boost::call_traits::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 +template +void +boost::python::indexing::base_container_traits +::visitor_helper (PythonClass &pyClass, Policy const &policy) +{ + value_traits_::visitor_helper (pyClass, policy); +} + +#endif // container_suite_rmg_20030823_included diff --git a/include/boost/python/suite/indexing/element_proxy.hpp b/include/boost/python/suite/indexing/element_proxy.hpp new file mode 100755 index 00000000..58b2fe0a --- /dev/null +++ b/include/boost/python/suite/indexing/element_proxy.hpp @@ -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 +#include + +#include +#include +#include +#include + +namespace boost { namespace python { namespace indexing { + template + class element_proxy + { + template friend struct const_element_proxy; + + typedef ContainerProxy container_proxy; + typedef typename container_proxy::shared_proxy proxy_type; + typedef boost::shared_ptr 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 ©) + { + 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 ©) + { + // 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 + struct const_element_proxy + { + typedef ContainerProxy container_proxy; + typedef typename container_proxy::shared_proxy proxy_type; + typedef boost::shared_ptr 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 const ©) + : 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::raw_value_type * + get_pointer (python::indexing::element_proxy const &proxy) + { + return &(*proxy); + } +} + +namespace boost { namespace python { namespace indexing { + template + struct value_traits > + : public value_traits + { + template + static void visitor_helper (PythonClass &, Policy const &) + { + typedef element_proxy element_proxy_; + typedef typename ContainerProxy::raw_value_type raw_value_type; + + boost::python::register_ptr_to_python(); + boost::python::implicitly_convertible(); + } + }; +} } } + +#endif // element_proxy_rmg_20030915_included diff --git a/include/boost/python/suite/indexing/iterator_pair.hpp b/include/boost/python/suite/indexing/iterator_pair.hpp new file mode 100755 index 00000000..59c2c9e5 --- /dev/null +++ b/include/boost/python/suite/indexing/iterator_pair.hpp @@ -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 +#include +#include +#include + +namespace boost { namespace python { namespace indexing { + template + class iterator_pair + { + private: + typedef typename boost::call_traits::param_type iterator_param; + typedef std::iterator_traits 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 + iterator_pair::iterator_pair (iterator_param begin + , iterator_param end) + : myBegin (begin) + , myEnd (end) + { + } + + template + typename iterator_pair::iterator + iterator_pair::begin() const + { + return myBegin; + } + + template + typename iterator_pair::iterator + iterator_pair::end() const + { + return myEnd; + } + + template + typename iterator_pair::size_type + iterator_pair::size() const + { + return std::distance (begin(), end()); + } + + template + typename iterator_pair::reference + iterator_pair::operator[](size_type index) const + { + iterator temp (begin()); + std::advance (temp, index); + return *temp; + } + + template + typename iterator_pair::reference + iterator_pair::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 + T *begin (T(&array)[N]) { + return array; + } + + template + T *end (T(&array)[N]) { + return array + N; + } +} } } + +#endif // iterator_pair_rmg_20030909_included diff --git a/include/boost/python/suite/indexing/iterator_traits.hpp b/include/boost/python/suite/indexing/iterator_traits.hpp new file mode 100755 index 00000000..6a583ef6 --- /dev/null +++ b/include/boost/python/suite/indexing/iterator_traits.hpp @@ -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 + +#include +#include +#include + +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 + struct input_iterator_traits + { + private: + typedef std::iterator_traits 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::value); + + BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_none); + }; + + template + struct forward_iterator_traits + : public input_iterator_traits + { + BOOST_STATIC_CONSTANT (bool, has_copyable_iter = true); + }; + + template + struct bidirectional_iterator_traits + : public forward_iterator_traits + { + BOOST_STATIC_CONSTANT (bool, is_reorderable = has_mutable_ref); + }; + + template + struct random_access_iterator_traits + : public bidirectional_iterator_traits + { + 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 struct traits_by_size { }; + + template<> + struct traits_by_size { + template + struct traits { + typedef input_iterator_traits type; + }; + }; + + template<> + struct traits_by_size { + template + struct traits { + typedef forward_iterator_traits type; + }; + }; + + template<> + struct traits_by_size { + template + struct traits { + typedef bidirectional_iterator_traits type; + }; + }; + + template<> + struct traits_by_size { + template + struct traits { + typedef random_access_iterator_traits type; + }; + }; + + template + class traits_by_category { + typedef typename std::iterator_traits::iterator_category + iterator_category; + + BOOST_STATIC_CONSTANT (size_t, size + = sizeof(sizer(iterator_category()))); + + public: + typedef typename traits_by_size::traits::type type; + }; + } + + template + struct iterator_traits + : public iterator_detail::traits_by_category::type + { + }; +} } } + +#endif // iterator_traits_rmg_20030823_included diff --git a/include/boost/python/suite/indexing/python_iterator.hpp b/include/boost/python/suite/indexing/python_iterator.hpp new file mode 100755 index 00000000..0918d027 --- /dev/null +++ b/include/boost/python/suite/indexing/python_iterator.hpp @@ -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 +#include + +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 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 diff --git a/include/boost/python/suite/indexing/shared_proxy_impl.hpp b/include/boost/python/suite/indexing/shared_proxy_impl.hpp new file mode 100755 index 00000000..794e2654 --- /dev/null +++ b/include/boost/python/suite/indexing/shared_proxy_impl.hpp @@ -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 + +namespace boost { namespace python { namespace indexing { + template + 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 ©); + // Creates value-only (detached) proxy + + private: + template 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 myElementPtr; // When detached + + private: + // Not implemented + shared_proxy_impl (shared_proxy_impl const &); + shared_proxy_impl &operator= (shared_proxy_impl const &); + }; + + template + shared_proxy_impl::shared_proxy_impl (ContainerProxy *ownerPtr + , size_t index) + : myOwnerPtr (ownerPtr) + , myIndex (index) + , myElementPtr () + { + } + + template + shared_proxy_impl::shared_proxy_impl (value_type const &val) + : myOwnerPtr (0) + , myIndex (-1) + , myElementPtr (new value_type (val)) + { + } + + template + typename shared_proxy_impl::reference + shared_proxy_impl::operator* () const + { + return myOwnerPtr + ? myOwnerPtr->raw_container().at (myIndex) + : *myElementPtr; + } + + template + void shared_proxy_impl::detach () + { + myElementPtr.reset (new value_type (**this)); + myOwnerPtr = 0; + myIndex = static_cast(-1); + } +} } } + +#endif // shared_proxy_impl_rmg_20030829_included diff --git a/include/boost/python/suite/indexing/slice.hpp b/include/boost/python/suite/indexing/slice.hpp new file mode 100755 index 00000000..aac1df76 --- /dev/null +++ b/include/boost/python/suite/indexing/slice.hpp @@ -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 +#include + +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 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 +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 + : pytype_object_manager_traits<&PySlice_Type, ::boost::python::indexing::slice> + { + }; +}}} + +#endif // slice_rmg_20030910_included diff --git a/include/boost/python/suite/indexing/slice_handler.hpp b/include/boost/python/suite/indexing/slice_handler.hpp new file mode 100755 index 00000000..292e7737 --- /dev/null +++ b/include/boost/python/suite/indexing/slice_handler.hpp @@ -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 +#include +#include +#include +#include + +#include +#include + +namespace boost { namespace python { namespace indexing { + template + 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 struct maybe_insert { + template + 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 { + template + static void apply (typename Algorithms::container &c + , typename Algorithms::index_param i + , typename Algorithms::value_param v) + { + Algorithms::insert (c, i, v); + } + }; + + template struct maybe_erase { + template + 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 { + template + 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 + slice_handler + ::postcall_override::postcall_override (Policy const &p) + : mBase (p) + { + } + + ////////////////////////////////////////////////////////////////////////// + // precall forwarder + ////////////////////////////////////////////////////////////////////////// + + template + bool + slice_handler + ::postcall_override::precall (PyObject *args) + { + return mBase.precall (args); + } + + ////////////////////////////////////////////////////////////////////////// + // Apply base postcall to each element of the list returend by get_slice + ////////////////////////////////////////////////////////////////////////// + + template + PyObject * + slice_handler + ::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 + boost::python::object + slice_handler + ::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 + boost::python::object + slice_handler + ::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 + boost::python::object + slice_handler + ::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 + boost::python::object + slice_handler + ::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 + boost::python::list + slice_handler + ::get_slice (container &c, slice sl) + { + typedef typename Policy::result_converter converter_type; + typedef typename Algorithms::reference reference; + typename boost::mpl::apply1::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 + void + slice_handler + ::set_slice (container &c, slice sl, boost::python::object values) + { + std::auto_ptr 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 + extractor1; + + typedef boost::python::extract + 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 + ::template apply (c, index, ex1); + + Algorithms::assign (c, index, ex1); + } + + else + { + maybe_insert + ::template apply + (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 + ::template apply (c, index, sl.stop()); + } + } + } + + ////////////////////////////////////////////////////////////////////////// + // Implementation for the slice version of __delitem__ + ////////////////////////////////////////////////////////////////////////// + + template + void + slice_handler + ::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 + void + slice_handler + ::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 diff --git a/include/boost/python/suite/indexing/suite_utils.hpp b/include/boost/python/suite/indexing/suite_utils.hpp new file mode 100755 index 00000000..da91b0b5 --- /dev/null +++ b/include/boost/python/suite/indexing/suite_utils.hpp @@ -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 + +namespace boost { namespace python { namespace indexing { + template + class is_mutable_ref + { + typedef typename boost::remove_reference::type maybe_const; + + public: + static bool const value = ! boost::is_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 struct make_signed { + typedef T type; + }; + + template<> struct make_signed { + // Raw "char" could be signed or unsigned. "signed char" + // guarantess signedness + typedef signed char type; + }; + + template<> struct make_signed { + typedef signed char type; + }; + + template<> struct make_signed { + typedef short type; + }; + + template<> struct make_signed { + typedef int type; + }; + + template<> struct make_signed { + typedef long type; + }; + +#if defined (BOOST_HAS_LONG_LONG) + template<> struct make_signed { + typedef long long type; + }; +#elif defined (BOOST_HAS_MS_INT64) + template<> struct make_signed { + typedef __int64 type; + }; +#endif +} } } + +#endif // suite_utils_rmg_20030823_included diff --git a/include/boost/python/suite/indexing/value_traits.hpp b/include/boost/python/suite/indexing/value_traits.hpp new file mode 100755 index 00000000..79f3a145 --- /dev/null +++ b/include/boost/python/suite/indexing/value_traits.hpp @@ -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 + 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 + static void visitor_helper (PythonClass &, Policy const &) { } + }; +} } } + +#endif // value_traits_rmg_20030912_included diff --git a/include/boost/python/suite/indexing/visitor.hpp b/include/boost/python/suite/indexing/visitor.hpp new file mode 100755 index 00000000..8494de6d --- /dev/null +++ b/include/boost/python/suite/indexing/visitor.hpp @@ -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 + +#include +#include +#include +#include + +namespace boost { namespace python { namespace indexing { + namespace detail { + template + 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 ©) : 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 + struct maybe_add_len { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // __len__ real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_len { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__len__", &Algorithms::size, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // __getitem__ dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_getitem { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // __getitem__ no-slice + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_getitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__getitem__", &Algorithms::get, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // __getitem__ with slice + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_getitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__getitem__", &Algorithms::get, policy); + pyClass.def ("__getitem__" + , slice_handler::make_getitem (policy)); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // __setitem__ dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_setitem { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // __setitem__ no-slice + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_setitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__setitem__", &Algorithms::assign, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // __setitem__ with slice + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_setitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__setitem__", &Algorithms::assign, policy); + pyClass.def ("__setitem__" + , slice_handler::make_setitem (policy)); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // __delitem__ dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_delitem { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // __delitem__ no-slice + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_delitem { + template + 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 { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__delitem__", &Algorithms::erase_one, policy); + pyClass.def ("__delitem__" + , slice_handler::make_delitem (policy)); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // __iter__ dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_iter { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // __iter__ real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_iter { + template + 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 (Algorithms::begin + , Algorithms::end)); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // sort dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_sort { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // sort real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_sort { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("sort", &Algorithms::sort, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // reverse dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_reverse { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // reverse real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_reverse { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("reverse", &Algorithms::reverse, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // append dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_append { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // append real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_append { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("append", &Algorithms::push_back, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // extend dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_insert { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // insert real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_insert { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("insert", Algorithms::insert, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // extend dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_extend { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // extend real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_extend { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("extend" + , slice_handler::make_extend (policy)); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // index dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_index { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // index real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_index { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("index", Algorithms::get_index, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // count dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_count { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // count real (sequences without indexing) + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_count { + template + 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 { + template + 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 + // + pyClass.def ("count", Algorithms::count, policy); + pyClass.def ("__contains__", Algorithms::contains, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // count real (associative containers). add has_key + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_count { + template + 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 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 + void visit (PythonClass &pyClass) const + { + detail::precall_only 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 + ::apply (pyClass, algorithms(), precallPolicy); + + maybe_add_getitem + ::apply (pyClass, algorithms(), mPolicy); + + maybe_add_setitem + ::apply (pyClass, algorithms(), mPolicy); + + maybe_add_delitem + ::apply (pyClass, algorithms(), mPolicy); + + maybe_add_iter<((traits::index_style != index_style_linear) + && traits::has_copyable_iter)> + ::apply (pyClass, algorithms(), mPolicy); + + maybe_add_sort + ::apply (pyClass, algorithms(), precallPolicy); + + maybe_add_reverse + ::apply (pyClass, algorithms(), precallPolicy); + + maybe_add_append + ::apply (pyClass, algorithms(), precallPolicy); + + maybe_add_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 + ::apply (pyClass, algorithms(), precallPolicy); + + Algorithms::visitor_helper (pyClass, mPolicy); + } + }; +} } } + +#endif // visitor_rmg_20030823_included