// 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 // 2003/10/28 rmg Split container-specific versions into separate headers // 2006/10/25 Roman Adding keys function to assoc_algorithms class // 2008/12/08 Roman Change indexing suite layout // // $Id: algorithms.hpp,v 1.1.2.15 2004/02/08 18:57:42 raoulgough Exp $ // #ifndef BOOST_PYTHON_INDEXING_ALGORITHMS_HPP #define BOOST_PYTHON_INDEXING_ALGORITHMS_HPP #include <indexing_suite/suite_utils.hpp> #include <boost/type_traits.hpp> #include <boost/python/errors.hpp> #include <indexing_suite/int_slice_helper.hpp> #include <indexing_suite/slice.hpp> #include <boost/mpl/if.hpp> #include <boost/limits.hpp> #include <algorithm> #include <functional> #include <stdexcept> #include <string> #include <set> namespace boost { namespace python { namespace indexing { template<typename ContainerTraits, typename Ovr = detail::no_override> class default_algorithms { typedef default_algorithms<ContainerTraits, Ovr> self_type; typedef typename detail::maybe_override<self_type, Ovr> ::type most_derived; public: 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; // Defer selection of supported_methods to the ContainerTraits // template argument. This makes sense because default_algorithms // derives all of its other information from this argument, and // can't decide which of the static member functions will // instantiate successfully for the container. Obviously a // custom-written Algorithms implementation could choose to // provide the supported_methods directly. BOOST_STATIC_CONSTANT( method_set_type, supported_methods = ContainerTraits::supported_methods); 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(); } // Reasonable defaults for slice handling typedef int_slice_helper<self_type, integer_slice> slice_helper; static slice_helper make_slice_helper (container &c, slice const &); // Default visit_container_class template<typename PythonClass, typename Policy> static void visit_container_class( PythonClass &pyClass, Policy const &policy) { container_traits::visit_container_class (pyClass, policy); } #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) // MSVC6 and 7.0 seem to complain about most_derived::bounds_check // for an instantiation of list_algorithms. public: #else private: #endif 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. }; ///////////////////////////////////////////////////////////////////////// // Base class for associative containers ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr = detail::no_override> class assoc_algorithms : public default_algorithms <ContainerTraits, BOOST_DEDUCED_TYPENAME detail::maybe_override <assoc_algorithms<ContainerTraits, Ovr>, Ovr> ::type> { typedef assoc_algorithms<ContainerTraits, Ovr> self_type; typedef typename detail::maybe_override<self_type, Ovr> ::type most_derived; typedef default_algorithms<ContainerTraits, most_derived> 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); // Default visit_container_class template<typename PythonClass, typename Policy> static void visit_container_class( PythonClass &pyClass, Policy const &policy) { ContainerTraits::visit_container_class (pyClass, policy); } protected: static iterator find_or_throw (container &, index_param); }; ///////////////////////////////////////////////////////////////////////// // Get the size of a container ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME default_algorithms<ContainerTraits, Ovr>::size_type default_algorithms<ContainerTraits, Ovr>::size (container &c) { return c.size(); } ///////////////////////////////////////////////////////////////////////// // Range check an index and throw out_of_range if necessary ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME default_algorithms<ContainerTraits, Ovr>::size_type default_algorithms<ContainerTraits, Ovr>::bounds_check( container &c, index_param ix, char const *msg, bool one_past, bool truncate) { size_type bound = most_derived::size(c) + (one_past ? 1 : 0); size_type result; if (truncate) { if (ix < 0) { result = 0; } else { result = ix; if ((result >= bound) && (bound > 0)) { result = bound - 1; } } } else if (ix < 0) { if (size_type(-ix) > bound) { throw std::out_of_range (msg); } result = bound + ix; } else { result = ix; } if (result >= bound) { throw std::out_of_range (msg); } return result; } ///////////////////////////////////////////////////////////////////////// // Find an element in a container (std algorithm version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME default_algorithms<ContainerTraits, Ovr>::iterator default_algorithms<ContainerTraits, Ovr>::find( container &c, key_param key) { typedef typename container_traits::value_traits_type vtraits; typedef typename vtraits::equal_to comparison; return std::find_if( most_derived::begin(c), most_derived::end(c), std::bind1st (comparison(), key)); } ///////////////////////////////////////////////////////////////////////// // Find an element and return its index (std algorithm version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME default_algorithms<ContainerTraits, Ovr>::size_type default_algorithms<ContainerTraits, Ovr>::get_index( container &c, key_param key) { iterator found (most_derived::find (c, key)); if (found == most_derived::end(c)) { PyErr_SetString( PyExc_ValueError, "get_index: element not found"); boost::python::throw_error_already_set (); } iterator start (most_derived::begin (c)); return std::distance (start, found); } ///////////////////////////////////////////////////////////////////////// // Count occurances of an element in a container (std algorithm version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME default_algorithms<ContainerTraits, Ovr>::size_type default_algorithms<ContainerTraits, Ovr>::count( container &c, key_param key) { typedef typename container_traits::value_traits_type vtraits; typedef typename vtraits::equal_to comparison; return std::count_if( most_derived::begin(c), most_derived::end(c), std::bind1st (comparison(), key)); } ///////////////////////////////////////////////////////////////////////// // Check whether a container contains the given element (std algo ver) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> bool default_algorithms<ContainerTraits, Ovr>::contains( container &c, key_param key) { return most_derived::find (c, key) != most_derived::end(c); } ///////////////////////////////////////////////////////////////////////// // Index into a container (generic version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME default_algorithms<ContainerTraits, Ovr>::reference default_algorithms<ContainerTraits, Ovr>::get( container &c, index_param ix) { return c[most_derived::bounds_check (c, ix, "get")]; } ///////////////////////////////////////////////////////////////////////// // Assign a value at a particular index (generic version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void default_algorithms<ContainerTraits, Ovr>::assign( container &c, index_param ix, value_param val) { c[most_derived::bounds_check (c, ix, "assign")] = val; } ///////////////////////////////////////////////////////////////////////// // Insert at end of a container (generic version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void default_algorithms<ContainerTraits, Ovr>::push_back( container &c, value_param v) { c.push_back (v); } ///////////////////////////////////////////////////////////////////////// // Insert at an index in the container (generic version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void default_algorithms<ContainerTraits, Ovr>::insert( container &c, index_param i, value_param v) { iterator insert_pos (most_derived::begin(c)); // Index may range up to c.size() inclusive to allow inserting at end std::advance( insert_pos, most_derived::bounds_check (c, i, "insert", true, true)); c.insert (insert_pos, v); } ///////////////////////////////////////////////////////////////////////// // Erase between given indexes in the container (generic version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void default_algorithms<ContainerTraits, Ovr>::erase_range( container &c, index_param from, index_param to) { iterator start (most_derived::begin(c)); iterator finish (most_derived::begin(c)); // Start index must be properly in bounds std::advance (start, most_derived::bounds_check (c, from, "erase_range (from)")); // End index is one-past-the-end, so may range up to c.size() inclusive std::advance (finish, most_derived::bounds_check (c, to, "erase_range (to)", true)); c.erase (start, finish); } ///////////////////////////////////////////////////////////////////////// // Erase one element at the given index in the container (generic version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void default_algorithms<ContainerTraits, Ovr>::erase_one( container &c, index_param ix) { iterator iter (most_derived::begin(c)); std::advance (iter, most_derived::bounds_check (c, ix, "erase_one")); c.erase (iter); } ///////////////////////////////////////////////////////////////////////// // Reverse the contents of a container (std algorithm version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void default_algorithms<ContainerTraits, Ovr>::reverse (container &c) { std::reverse (most_derived::begin(c), most_derived::end(c)); } ///////////////////////////////////////////////////////////////////////// // Sort the contents of a container (std algorithm version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void default_algorithms<ContainerTraits, Ovr>::sort (container &c) { typedef typename container_traits::value_traits_type vtraits; typedef typename vtraits::less comparison; std::sort (most_derived::begin(c), most_derived::end(c), comparison()); } ///////////////////////////////////////////////////////////////////////// // slice_helper factory function (default version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME default_algorithms<ContainerTraits, Ovr>::slice_helper default_algorithms<ContainerTraits, Ovr> ::make_slice_helper (container &c, slice const &sl) { return slice_helper (c, integer_slice (sl, most_derived::size (c))); } ///////////////////////////////////////////////////////////////////////// // Index into a container (associative version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME assoc_algorithms<ContainerTraits, Ovr>::reference assoc_algorithms<ContainerTraits, Ovr>::get (container &c, index_param ix) { return *most_derived::find_or_throw (c, ix); } ///////////////////////////////////////////////////////////////////////// // Erase elements with the given key (associative version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void assoc_algorithms<ContainerTraits, Ovr>::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 (); } } ///////////////////////////////////////////////////////////////////////// // Find an element in an associative container ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME assoc_algorithms<ContainerTraits, Ovr>::iterator assoc_algorithms<ContainerTraits, Ovr> ::find (container &c, key_param key) { return c.find (key); } ///////////////////////////////////////////////////////////////////////// // Find an element in an associative container ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> bool assoc_algorithms<ContainerTraits, Ovr>::contains( container &c, key_param key) { return most_derived::find (c, key) != most_derived::end(c); } ///////////////////////////////////////////////////////////////////////// // Find an element in an associative container - throw an exception if // not found ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME assoc_algorithms<ContainerTraits, Ovr>::iterator assoc_algorithms<ContainerTraits, Ovr>::find_or_throw( container &c, index_param ix) { iterator iter = most_derived::find (c, ix); if (iter == most_derived::end(c)) { PyErr_SetString( PyExc_ValueError, "associative container: key not found"); boost::python::throw_error_already_set (); } return iter; } ///////////////////////////////////////////////////////////////////////// // Count occurances of an element in a container (associative version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME assoc_algorithms<ContainerTraits, Ovr>::size_type assoc_algorithms<ContainerTraits, Ovr>::count( container &c, key_param key) { return c.count (key); } ///////////////////////////////////////////////////////////////////////// // Some meta-information to select algorithms for const and // non-const qualified containers. All algorithms_selector specializations // include two publically accessible typedefs, called // mutable_algorithms and const_algorithms. This saves having to // have separate partial specializations of algorithms for // const and non-const containers. Client code should probably // specialize algorithms directly. ///////////////////////////////////////////////////////////////////////// namespace detail { template<typename Container> class algorithms_selector # if defined(BOOST_MPL_MSVC_ETI_BUG) { // Bogus types to prevent compile errors due to ETI typedef algorithms_selector<Container> mutable_algorithms; typedef algorithms_selector<Container> const_algorithms; } # endif ; } ///////////////////////////////////////////////////////////////////////// // Algorithms selection for mutable containers ///////////////////////////////////////////////////////////////////////// template<class Container> struct algorithms : public detail::algorithms_selector<Container>::mutable_algorithms { }; # if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) ///////////////////////////////////////////////////////////////////////// // Algorithms selection for const-qualified containers ///////////////////////////////////////////////////////////////////////// template<class Container> struct algorithms<Container const> : public detail::algorithms_selector<Container>::const_algorithms { }; # endif } } } #endif // BOOST_PYTHON_INDEXING_ALGORITHMS_HPP