/* ///////////////////////////////////////////////////////////////////////// * File: rangelib/algorithms.hpp * * Purpose: Range algorithms. * * Created: 4th November 2003 * Updated: 5th March 2011 * * Thanks to: Pablo Aguilar for requesting r_copy_if(); to Luoyi, for pointing * out some gaps in the compatibility with the sequence_range; to * Yakov Markovitch for spotting a bug in r_exists_if_1_impl(). * * Home: http://stlsoft.org/ * * Copyright (c) 2003-2011, Matthew Wilson and Synesis Software * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of * any contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * ////////////////////////////////////////////////////////////////////// */ /** \file rangelib/algorithms.hpp Range algorithms * * This file includes the definition of the following algorithms: * * - r_accumulate() * - r_accumulate() * - r_copy() * - r_copy_if() * - r_count() * - r_count_if() * - r_distance() * - r_equal() * - r_exists() * - r_exists_if() * - r_fill() * - r_fill_n() * - r_find() * - r_find_if() * - r_for_each() * - r_generate() * - r_max_element() * - r_min_element() * - r_replace() * - r_replace_copy() * - r_replace_if() * - r_replace_copy_if() */ #ifndef RANGELIB_INCL_RANGELIB_HPP_ALGORITHMS #define RANGELIB_INCL_RANGELIB_HPP_ALGORITHMS #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define RANGELIB_VER_RANGELIB_HPP_ALGORITHMS_MAJOR 2 # define RANGELIB_VER_RANGELIB_HPP_ALGORITHMS_MINOR 3 # define RANGELIB_VER_RANGELIB_HPP_ALGORITHMS_REVISION 6 # define RANGELIB_VER_RANGELIB_HPP_ALGORITHMS_EDIT 46 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /* ///////////////////////////////////////////////////////////////////////// * Auto-generation and compatibility */ /* [Incompatibilies-start] STLSOFT_COMPILER_IS_MSVC: _MSC_VER < 1200 STLSOFT_COMPILER_IS_MWERKS: (__MWERKS__ & 0xFF00) < 0x3000 [Incompatibilies-end] */ /* ///////////////////////////////////////////////////////////////////////// * Includes */ #ifndef RANGELIB_INCL_RANGELIB_HPP_RANGELIB # include #endif /* !RANGELIB_INCL_RANGELIB_HPP_RANGELIB */ #ifndef RANGELIB_INCL_RANGELIB_HPP_RANGE_CATEGORIES # include #endif /* !RANGELIB_INCL_RANGELIB_HPP_RANGE_CATEGORIES */ #ifndef RANGELIB_INCL_RANGELIB_ERROR_HPP_EXCEPTIONS # include #endif /* !RANGELIB_INCL_RANGELIB_ERROR_HPP_EXCEPTIONS */ #ifndef RANGELIB_INCL_RANGELIB_HPP_BASIC_INDIRECT_RANGE_ADAPTOR # include #endif /* !RANGELIB_INCL_RANGELIB_HPP_BASIC_INDIRECT_RANGE_ADAPTOR */ #ifndef STLSOFT_INCL_ALGORITHM # define STLSOFT_INCL_ALGORITHM # include #endif /* !STLSOFT_INCL_ALGORITHM */ #ifndef STLSOFT_INCL_NUMERIC # define STLSOFT_INCL_NUMERIC # include #endif /* !STLSOFT_INCL_NUMERIC */ #ifdef STLSOFT_UNITTEST # include # include # include # include #endif /* STLSOFT_UNITTEST */ /* ///////////////////////////////////////////////////////////////////////// * Namespace */ #ifndef RANGELIB_NO_NAMESPACE # if defined(_STLSOFT_NO_NAMESPACE) || \ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) /* There is no stlsoft namespace, so must define ::rangelib */ namespace rangelib { # else /* Define stlsoft::rangelib_project */ namespace stlsoft { namespace rangelib_project { # endif /* _STLSOFT_NO_NAMESPACE */ #endif /* !RANGELIB_NO_NAMESPACE */ /* ///////////////////////////////////////////////////////////////////////// * Functions */ /* ********************************************************* * accumulate (2) */ template< ss_typename_param_k R , ss_typename_param_k T > inline T r_accumulate_2_impl(R r, T val, notional_range_tag const&) { for(; r; ++r) { val = val + *r; } return val; } template< ss_typename_param_k R , ss_typename_param_k T > inline T r_accumulate_2_impl(R r, T val, iterable_range_tag const&) { return std::accumulate(r.begin(), r.end(), val); } template< ss_typename_param_k R , ss_typename_param_k T > inline T r_accumulate_2_impl(R r, T val, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).accumulate(val); } template< ss_typename_param_k R , ss_typename_param_k T > inline T r_accumulate_2_impl(R r, T val, indirect_range_tag const&) { return r.accumulate(val); } /** \brief accumulate() for ranges * * \ingroup group__library__rangelib * * \param r The range * \param val The initial value * \retval The sum of the accumulate items and the initial value * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k T > inline T r_accumulate(R r, T val) { return r_accumulate_2_impl(r, val, r); } /* ********************************************************* * accumulate (3) */ template< ss_typename_param_k R , ss_typename_param_k T , ss_typename_param_k P > inline T r_accumulate_3_impl(R r, T val, P pred, notional_range_tag const&) { for(; r; ++r) { val = pred(val, *r); } return val; } template< ss_typename_param_k R , ss_typename_param_k T , ss_typename_param_k P > inline T r_accumulate_3_impl(R r, T val, P pred, iterable_range_tag const&) { return std::accumulate(r.begin(), r.end(), val, pred); } template< ss_typename_param_k R , ss_typename_param_k T , ss_typename_param_k P > inline T r_accumulate_2_impl(R r, T val, P pred, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).accumulate(val, pred); } template< ss_typename_param_k R , ss_typename_param_k T , ss_typename_param_k P > inline T r_accumulate_3_impl(R r, T val, P pred, indirect_range_tag const&) { return r.accumulate(val, pred); } /** \brief accumulate() for ranges * * \ingroup group__library__rangelib * * \param r The range * \param val The initial value * \param pred The predicate applied to each entry * \retval The sum of the accumulate items and the initial value * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k T , ss_typename_param_k P > inline T r_accumulate(R r, T val, P pred) { return r_accumulate_3_impl(r, val, pred, r); } /* ********************************************************* * copy */ template< ss_typename_param_k R , ss_typename_param_k O > inline O r_copy_impl(R r, O o, notional_range_tag const&) { for(; r; ++r, ++o) { *o = *r; } return o; } template< ss_typename_param_k R , ss_typename_param_k O > inline O r_copy_impl(R r, O o, iterable_range_tag const&) { return std::copy(r.begin(), r.end(), o); } template< ss_typename_param_k R , ss_typename_param_k O > inline O r_copy_impl(R r, O o, indirect_range_tag const&) { return r.copy(o); } template< ss_typename_param_k R , ss_typename_param_k O > inline O r_copy_impl(R r, O o, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).copy(o); } /** \brief Copies the contents of the range to the output iterator * * \ingroup group__library__rangelib * * \param r The range whose elements are to be copied * \param o The output iterator to receive the elements * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k O > inline O r_copy(R r, O o) { return r_copy_impl(r, o, r); } /* ********************************************************* * copy_if */ template< ss_typename_param_k R , ss_typename_param_k O , ss_typename_param_k P > inline O r_copy_if_impl(R r, O o, P pred, notional_range_tag const&) { for(; r; ++r) { if(pred(*r)) { *o = *r; ++o; } } return o; } #if 0 /* Not defined, since copy_if() is not in standard, so we reuse the Notional Range implementation */ template< ss_typename_param_k R , ss_typename_param_k O , ss_typename_param_k P > inline O r_copy_if_impl(R r, O o, P pred, iterable_range_tag const&) { return std::copy_if(r.begin(), r.end(), o); } #endif /* 0 */ template< ss_typename_param_k R , ss_typename_param_k O , ss_typename_param_k P > inline O r_copy_if_impl(R r, O o, P pred, indirect_range_tag const&) { return r.copy_if(o); } template< ss_typename_param_k R , ss_typename_param_k O , ss_typename_param_k P > inline O r_copy_if_impl(R r, O o, P pred, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).copy_if(o); } /** \brief Copies the contents of the range to the output iterator * * \ingroup group__library__rangelib * * \param r The range whose elements are to be copied * \param o The output iterator to receive the elements * \param pred The predicate used to select the elements * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k O , ss_typename_param_k P > inline O r_copy_if(R r, O o, P pred) { return r_copy_if_impl(r, o, pred, r); } /* ********************************************************* * count */ template< ss_typename_param_k R , ss_typename_param_k T > inline ss_size_t r_count_impl(R r, T const& val, notional_range_tag const&) { ss_size_t n; for(n = 0; r; ++r) { if(val == *r) { ++n; } } return n; } template< ss_typename_param_k R , ss_typename_param_k T > inline ss_size_t r_count_impl(R r, T const& val, iterable_range_tag const&) { return std::count(r.begin(), r.end(), val); } template< ss_typename_param_k R , ss_typename_param_k T > inline ss_size_t r_count_impl(R r, T const& val, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).count(val); } template< ss_typename_param_k R , ss_typename_param_k T > inline ss_size_t r_count_impl(R r, T const& val, indirect_range_tag const&) { return r.count(val); } /** \brief Counts the number of instances of a given value in the range * * \ingroup group__library__rangelib * * \param r The range * \param val The value to search for * \retval The number of elements in the range matching \c val * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k T > inline ss_size_t r_count(R r, T const& val) { return r_count_impl(r, val, r); } /* ********************************************************* * count_if */ template< ss_typename_param_k R , ss_typename_param_k P > inline ss_size_t r_count_if_impl(R r, P pred, notional_range_tag const&) { ss_size_t n; for(n = 0; r; ++r) { if(pred(*r)) { ++n; } } return n; } template< ss_typename_param_k R , ss_typename_param_k P > inline ss_size_t r_count_if_impl(R r, P pred, iterable_range_tag const&) { return std::count_if(r.begin(), r.end(), pred); } template< ss_typename_param_k R , ss_typename_param_k P > inline ss_size_t r_count_if_impl(R r, P pred, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).count_if(pred); } template< ss_typename_param_k R , ss_typename_param_k P > inline ss_size_t r_count_if_impl(R r, P pred, indirect_range_tag const&) { return r.count_if(pred); } /** \brief Counts the number of instances matching the given predicate in the range * * \ingroup group__library__rangelib * * \param r The range * \param pred The predicate applied to each entry * \retval The number of elements in the range matching \c val * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k P > inline ss_size_t r_count_if(R r, P pred) { return r_count_if_impl(r, pred, r); } /* ********************************************************* * distance */ template inline ss_ptrdiff_t r_distance_1_impl(R r, notional_range_tag const&) { ss_ptrdiff_t d = 0; for(; r; ++r, ++d) {} return d; } template inline ss_ptrdiff_t r_distance_1_impl(R r, iterable_range_tag const&) { return std::distance(r.begin(), r.end()); } template inline ss_ptrdiff_t r_distance_1_impl(R r, indirect_range_tag const&) { return r.distance(); } template inline ss_ptrdiff_t r_distance_1_impl(R r, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).distance(); } /** \brief Counts the number of instances in the range * * \ingroup group__library__rangelib * * \param r The range * \retval The number of elements in the range * * \note: Supports Notional, Iterable and Indirect Range types */ template inline ss_ptrdiff_t r_distance(R r) { return r_distance_1_impl(r, r); } /* ********************************************************* * equal (2) */ template< ss_typename_param_k R1 , ss_typename_param_k R2 > inline ss_bool_t r_equal_1_impl(R1 r1, R2 r2, notional_range_tag const&, notional_range_tag const&) { for(; r1 && r2; ++r1, ++r2) { if(*r1 != *r2) { return false; } } return true; } template< ss_typename_param_k R1 , ss_typename_param_k R2 > inline ss_bool_t r_equal_1_impl(R1 r1, R2 r2, iterable_range_tag const&, iterable_range_tag const&) { return std::equal(r1.begin(), r1.end(), r2.begin()); } /** \brief Determines whether two ranges are equal * * \ingroup group__library__rangelib * * \param r1 The first range to compare * \param r2 The second range to compare * \retval true if the first N elements in the second range match the N * elements in the first range. If the first range contains more * elements than the second, then this function always returns false. * * \note: Supports Notional and Iterable Range types */ template< ss_typename_param_k R1 , ss_typename_param_k R2 > inline ss_bool_t r_equal(R1 r1, R2 r2) { if(r_distance(r1) > r_distance(r2)) { return false; } return r_equal_1_impl(r1, r2, r1, r2); } /* ********************************************************* * equal (3) */ template< ss_typename_param_k R1 , ss_typename_param_k R2 , ss_typename_param_k P > inline ss_bool_t r_equal_1_impl(R1 r1, R2 r2, P pred, notional_range_tag const&, notional_range_tag const&) { for(; r1 && r2; ++r1, ++r2) { if(!pred(*r1, *r2)) { return false; } } return true; } template< ss_typename_param_k R1 , ss_typename_param_k R2 , ss_typename_param_k P > inline ss_bool_t r_equal_1_impl(R1 r1, R2 r2, P pred, iterable_range_tag const&, iterable_range_tag const&) { return std::equal(r1.begin(), r1.end(), r2.begin(), pred); } /** \brief Determines whether two ranges are equal, as defined by a predicate * * \ingroup group__library__rangelib * * \param r1 The first range to compare * \param r2 The second range to compare * \param pred The predicate which evaluates matches between elements of the two ranges * \retval true if the first N elements in the second range match the N elements in the first range. * * \note: Supports Notional and Iterable Range types */ template< ss_typename_param_k R1 , ss_typename_param_k R2 , ss_typename_param_k P > inline ss_bool_t r_equal(R1 r1, R2 r2, P pred) { STLSOFT_ASSERT(r_distance(r1) <= r_distance(r2)); return r_equal_1_impl(r1, r2, pred, r1, r2); } /* ********************************************************* * exists */ template< ss_typename_param_k R , ss_typename_param_k T > inline ss_bool_t r_exists_impl(R r, T const& val, notional_range_tag const&) { for(; r; ++r) { if(val == *r) { return true; } } return false; } template< ss_typename_param_k R , ss_typename_param_k T > inline ss_bool_t r_exists_impl(R r, T const& val, iterable_range_tag const&) { return std::find(r.begin(), r.end(), val) != r.end(); } template< ss_typename_param_k R , ss_typename_param_k T > inline ss_bool_t r_exists_impl(R r, T const& val, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).exists(val); } template< ss_typename_param_k R , ss_typename_param_k T > inline ss_bool_t r_exists_impl(R r, T const& val, indirect_range_tag const&) { return r.exists(val); } /** \brief Determines whether the given value exists in the range * * \ingroup group__library__rangelib * * \param r The range * \param val The value to search for * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k T > inline ss_bool_t r_exists(R r, T const& val) { return r_exists_impl(r, val, r); } /* ********************************************************* * exists_if (1) */ template< ss_typename_param_k R , ss_typename_param_k P > inline ss_bool_t r_exists_if_1_impl(R r, P pred, notional_range_tag const&) { for(; r; ++r) { if(pred(*r)) { return true; } } return false; } template< ss_typename_param_k R , ss_typename_param_k P > inline ss_bool_t r_exists_if_1_impl(R r, P pred, iterable_range_tag const&) { return std::find_if(r.begin(), r.end(), pred) != r.end(); } template< ss_typename_param_k R , ss_typename_param_k P > inline ss_bool_t r_exists_if_1_impl(R r, P pred, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).exists_if(pred); } template< ss_typename_param_k R , ss_typename_param_k P > inline ss_bool_t r_exists_if_1_impl(R r, P pred, indirect_range_tag const&) { return r.exists_if(pred); } /** \brief Determines whether a value matching the given predicate exists in the range * * \ingroup group__library__rangelib * * \param r The range * \param pred The predicate used to match the items * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k P > inline ss_bool_t r_exists_if(R r, P pred) { return r_exists_if_1_impl(r, pred, r); } /* ********************************************************* * exists_if (2) */ template< ss_typename_param_k R , ss_typename_param_k P , ss_typename_param_k T > inline ss_bool_t r_exists_if_2_impl(R r, P pred, T &result, notional_range_tag const&) { for(; r; ++r) { if(pred(*r)) { result = *r; return true; } } return false; } template< ss_typename_param_k I , ss_typename_param_k V > inline ss_bool_t r_exists_if_2_impl_helper_(I from, I to, V &val) { if(from == to) { return false; } else { val = *from; return true; } } template< ss_typename_param_k R , ss_typename_param_k P , ss_typename_param_k T > inline ss_bool_t r_exists_if_2_impl(R r, P pred, T &result, iterable_range_tag const&) { return r_exists_if_2_impl_helper_(std::find_if(r.begin(), r.end(), pred), r.end()); } template< ss_typename_param_k R , ss_typename_param_k P , ss_typename_param_k T > inline ss_bool_t r_exists_if_2_impl(R r, P pred, T &result, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).exists_if(pred, result); } template< ss_typename_param_k R , ss_typename_param_k P , ss_typename_param_k T > inline ss_bool_t r_exists_if_2_impl(R r, P pred, T &result, indirect_range_tag const&) { return r.exists_if(pred, result); } /** \brief Determines whether a value matching the given predicate exists in the range * * \ingroup group__library__rangelib * * \param r The range * \param pred The predicate used to match the items * \param result The returned result * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k P , ss_typename_param_k T > inline R r_exists_if(R r, P pred, T &result) { return r_exists_if_2_impl(r, pred, result, r); } /* ********************************************************* * fill */ template< ss_typename_param_k R , ss_typename_param_k T > inline void r_fill_impl(R r, T const& val, iterable_range_tag const&) { std::fill(r.begin(), r.end(), val); } /** \brief Sets the elements in the range to the given value * * \ingroup group__library__rangelib * * \param r The range * \param val The value to assign to all elements in the range * * \note: Supports Iterable Range type */ template< ss_typename_param_k R , ss_typename_param_k T > inline void r_fill(R r, T const& val) { r_fill_impl(r, val, r); } /* ********************************************************* * fill_n */ template< ss_typename_param_k R , ss_typename_param_k S , ss_typename_param_k T > inline void r_fill_n_impl(R r, S n, T const& val, iterable_range_tag const&) { std::fill(r.begin(), n, val); } /** \brief Sets the first \c n elements in the range to the given value * * \ingroup group__library__rangelib * * \param r The range * \param n The number of elements to set. This must be <= r_distance(r) * \param val The value to assign to all elements in the range * * \note: Supports Iterable Range type */ template< ss_typename_param_k R , ss_typename_param_k S , ss_typename_param_k T > inline void r_fill_n(R r, S n, T const& val) { STLSOFT_ASSERT(n <= r_distance(r)); r_fill_1_impl(r, n, val, r); } /* ********************************************************* * find */ template< ss_typename_param_k R , ss_typename_param_k T > inline R r_find_impl(R r, T const& val, notional_range_tag const&) { for(; r; ++r) { if(val == *r) { break; } } return r; } template< ss_typename_param_k R , ss_typename_param_k T > inline R r_find_impl(R r, T const& val, iterable_range_tag const&) { return R(std::find(r.begin(), r.end(), val), r.end()); } /** \brief Finds the first instance of the given value in the range * * \ingroup group__library__rangelib * * \param r The range * \param val The value to find * * \note: Supports Notional and Iterable Range types */ template< ss_typename_param_k R , ss_typename_param_k T > inline R r_find(R r, T const& val) { return r_find_impl(r, val, r); } /* ********************************************************* * find_if */ // find_if template< ss_typename_param_k R , ss_typename_param_k P > inline R r_find_if_impl(R r, P pred, notional_range_tag const&) { for(; r; ++r) { if(pred(*r)) { break; } } return r; } template< ss_typename_param_k R , ss_typename_param_k P > inline R r_find_if_impl(R r, P pred, iterable_range_tag const&) { return R(std::find_if(r.begin(), r.end(), pred), r.end()); } /** \brief Finds the first instance of a value in the range matching the given predicate * * \ingroup group__library__rangelib * * \param r The range * \param pred The value to find * * \note: Supports Notional and Iterable Range types */ template< ss_typename_param_k R , ss_typename_param_k P > inline R r_find_if(R r, P pred) { return r_find_if_impl(r, pred, r); } /* ********************************************************* * for_each */ template< ss_typename_param_k R , ss_typename_param_k F > inline F r_for_each_impl(R r, F f, notional_range_tag const&) { for(; r; ++r) { f(*r); } return f; } template< ss_typename_param_k R , ss_typename_param_k F > inline F r_for_each_impl(R r, F f, iterable_range_tag const&) { return std::for_each(r.begin(), r.end(), f); } template< ss_typename_param_k R , ss_typename_param_k F > inline F r_for_each_impl(R r, F f, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).for_each(f); } template< ss_typename_param_k R , ss_typename_param_k F > inline F r_for_each_impl(R r, F f, indirect_range_tag const&) { return r.for_each(f); } /** \brief Applies the given function to every element in the range * * \ingroup group__library__rangelib * * \param r The range * \param f The function to apply * * \note: Supports Notional, Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k F > inline F r_for_each(R r, F f) { return r_for_each_impl(r, f, r); } /* ********************************************************* * generate */ template< ss_typename_param_k R , ss_typename_param_k F > inline void r_generate_impl(R r, F f, iterable_range_tag const&) { std::generate(r.begin(), r.end(), f); } /** \brief Sets each element in the range to the result of the given function * * \ingroup group__library__rangelib * * \param r The range * \param f The generator function * * \note: Supports Iterable Range type */ template< ss_typename_param_k R , ss_typename_param_k F > inline void r_generate(R r, F f) { r_generate_impl(r, f, r); } /* ********************************************************* * max_element (1) */ template inline ss_typename_type_ret_k R::value_type r_max_element_1_impl(R r, notional_range_tag const&) { typedef ss_typename_type_k R::value_type value_type_t; value_type_t max_ = value_type_t(); for(; r; ++r) { if(max_ < *r) { max_ = *r; } } return max_; } template inline I r_max_element_1_impl_iterable(I from, I to) { if(from == to) { STLSOFT_THROW_X(empty_range_exception("Cannot determine maximum element of empty range")); } return std::max_element(from, to); } template inline ss_typename_type_ret_k R::value_type r_max_element_1_impl(R r, iterable_range_tag const&) { return *r_max_element_1_impl_iterable(r.begin(), r.end()); } template inline ss_typename_type_ret_k R::value_type r_max_element_1_impl(R r, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).max_element(); } template inline ss_typename_type_ret_k R::value_type r_max_element_1_impl(R r, indirect_range_tag const&) { return r.max_element(); } /** \brief Evaluates the maximum element in the range * * \ingroup group__library__rangelib * * \param r The range. Cannot be closed * * \note: Supports Notional, Iterable and Indirect Range types * \note: The behaviour is undefined if the range is closed */ template inline ss_typename_type_ret_k R::value_type r_max_element(R r) { STLSOFT_ASSERT(r_distance(r) > 0); return r_max_element_1_impl(r, r); } /* ********************************************************* * max_element (2) */ template< ss_typename_param_k I , ss_typename_param_k F > inline I r_max_element_2_impl_iterable(I from, I to, F f) { if(from == to) { STLSOFT_THROW_X(empty_range_exception("Cannot determine maximum element of empty range")); } return std::max_element(from, to, f); } template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_max_element_2_impl(R r, F f, iterable_range_tag const&) { return *r_max_element_2_impl_iterable(r.begin(), r.end(), f); } template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_max_element_2_impl(R r, F f, notional_range_tag const&) { typedef ss_typename_type_k R::value_type value_type_t; value_type_t max_ = value_type_t(); for(; r; ++r) { if(f(max_, *r)) { max_ = *r; } } return max_; } template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_max_element_2_impl(R r, F f, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).max_element(f); } template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_max_element_2_impl(R r, F f, indirect_range_tag const&) { return r.max_element(f); } /** \brief Evaluates the maximum element in the range evaluated according to the given function * * \ingroup group__library__rangelib * * \param r The range. Cannot be closed * \param f The function used to evaluate the ordering * * \note: Supports Notional, Iterable and Indirect Range types * \note: The behaviour is undefined if the range is closed */ template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_max_element(R r, F f) { STLSOFT_ASSERT(r_distance(r) > 0); return r_max_element_2_impl(r, f, r); } /* ********************************************************* * min_element (1) */ template inline ss_typename_type_ret_k R::value_type r_min_element_1_impl(R r, notional_range_tag const&) { typedef ss_typename_type_k R::value_type value_type_t; if(!r) { return value_type_t(); } else { value_type_t min_ = *r; for(; ++r; ) { if(*r < min_) { min_ = *r; } } return min_; } } template inline I r_min_element_1_impl_iterable(I from, I to) { if(from == to) { STLSOFT_THROW_X(empty_range_exception("Cannot determine minimum element of empty range")); } return std::min_element(from, to); } template inline ss_typename_type_ret_k R::value_type r_min_element_1_impl(R r, iterable_range_tag const&) { return *r_min_element_1_impl_iterable(r.begin(), r.end()); } template inline ss_typename_type_ret_k R::value_type r_min_element_1_impl(R r, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).min_element(); } template inline ss_typename_type_ret_k R::value_type r_min_element_1_impl(R r, indirect_range_tag const&) { return r.min_element(); } /** \brief Evaluates the minimum element in the range * * \ingroup group__library__rangelib * * \param r The range. Cannot be closed * * \note: Supports Notional, Iterable and Indirect Range types * \note: The behaviour is undefined if the range is closed */ template inline ss_typename_type_ret_k R::value_type r_min_element(R r) { STLSOFT_ASSERT(r_distance(r) > 0); return r_min_element_1_impl(r, r); } /* ********************************************************* * min_element (2) */ template< ss_typename_param_k I , ss_typename_param_k F > inline I r_min_element_2_impl_iterable(I from, I to, F f) { if(from == to) { STLSOFT_THROW_X(empty_range_exception("Cannot determine minimum element of empty range")); } return std::min_element(from, to, f); } template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_min_element_2_impl(R r, F f, iterable_range_tag const&) { return *r_min_element_2_impl_iterable(r.begin(), r.end(), f); } template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_min_element_2_impl(R r, F f, notional_range_tag const&) { typedef ss_typename_type_k R::value_type value_type_t; value_type_t min_ = value_type_t(); for(; r; ++r) { if(f(min_, *r)) { min_ = *r; } } return min_; } template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_min_element_2_impl(R r, F f, basic_indirect_range_tag const&) { return indirect_range_adaptor(r).min_element(f); } template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_min_element_2_impl(R r, F f, indirect_range_tag const&) { return r.min_element(f); } /** \brief Evaluates the minimum element in the range evaluated according to the given function * * \ingroup group__library__rangelib * * \param r The range. Cannot be closed * \param f The function used to evaluate the ordering * * \note: Supports Notional, Iterable and Indirect Range types * \note: The behaviour is undefined if the range is closed */ template< ss_typename_param_k R , ss_typename_param_k F > inline ss_typename_type_ret_k R::value_type r_min_element(R r, F f) { STLSOFT_ASSERT(r_distance(r) > 0); return r_min_element_2_impl(r, f, r); } /* ********************************************************* * replace */ template< ss_typename_param_k R , ss_typename_param_k T > inline void r_replace_impl(R r, T oldVal, T newVal, iterable_range_tag const&) { std::replace(r.begin(), r.end(), oldVal, newVal); } template< ss_typename_param_k R , ss_typename_param_k T > inline void r_replace_impl(R r, T oldVal, T newVal, indirect_range_tag const&) { r.replace(r, oldVal, newVal); } /** \brief Replaces all elements of the given old value with the new value * * \ingroup group__library__rangelib * * \param r The range * \param oldVal The value to search for * \param newVal The value to replace any elements with \c oldVal * * \note: Supports Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k T > inline void r_replace(R r, T oldVal, T newVal) { r_replace_impl(r, oldVal, newVal, r); } /* ********************************************************* * replace_copy */ #if 0 template< ss_typename_param_k RI , ss_typename_param_k RO , ss_typename_param_k T > inline void r_replace_copy_impl(RI ri, RO ro, T oldVal, T newVal, iterable_range_tag const&, iterable_range_tag const&) { std::replace_copy(ri.begin(), ri.end(), ro.begin(), oldVal, newVal); } template< ss_typename_param_k RI , ss_typename_param_k RO , ss_typename_param_k T > inline void r_replace_copy_impl(RI ri, RO ro, T oldVal, T newVal, indirect_range_tag const&, indirect_range_tag const&) { ri.replace_copy(ro, oldVal, newVal); } /** \brief Replaces all elements of the given old value with the new value * * \ingroup group__library__rangelib * * \param r The range * \param oldVal The value to search for * \param newVal The value to replace any elements with \c oldVal * * \note: Supports Iterable and Indirect Range types */ template< ss_typename_param_k RI , ss_typename_param_k RO , ss_typename_param_k T > inline void r_replace_copy(RI ri, RO ro, T oldVal, T newVal) { r_replace_copy_impl(ri, ro, oldVal, newVal, ri, ro); } #endif /* 0 */ /* ********************************************************* * replace_if */ template< ss_typename_param_k R , ss_typename_param_k P , ss_typename_param_k T > inline void r_replace_if_impl(R r, P pred, T newVal, iterable_range_tag const&) { std::replace_if(r.begin(), r.end(), pred, newVal); } template< ss_typename_param_k R , ss_typename_param_k P , ss_typename_param_k T > inline void r_replace_if_impl(R r, P pred, T newVal, indirect_range_tag const&) { r.replace_if(r, pred, newVal); } /** \brief Replaces all elements matching the given predicate with the new value * * \ingroup group__library__rangelib * * \param r The range * \param pred The predicate for matching the old values to replace * \param newVal The value to replace any elements which match the given predicate * * \note: Supports Iterable and Indirect Range types */ template< ss_typename_param_k R , ss_typename_param_k P , ss_typename_param_k T > inline void r_replace_if(R r, P pred, T newVal) { r_replace_if_impl(r, pred, newVal, r); } /* ********************************************************* * replace_copy_if */ #if 0 template< ss_typename_param_k RI , ss_typename_param_k RO , ss_typename_param_k P , ss_typename_param_k T > inline void r_replace_copy_if_impl(RI ri, RO ro, P pred, T newVal, iterable_range_tag const&, iterable_range_tag const&) { std::replace_copy_if(ri.begin(), ri.end(), ro.begin(), pred, newVal); } template< ss_typename_param_k RI , ss_typename_param_k RO , ss_typename_param_k P , ss_typename_param_k T > inline void r_replace_copy_if_impl(RI ri, RO ro, P pred, T newVal, notional_range_tag const&, notional_range_tag const&) { for(; ri; ++ri, ++ro) { STLSOFT_ASSERT(!(!ro)); if(pred(*ri)) { *ro = newVal; } } } template< ss_typename_param_k RI , ss_typename_param_k RO , ss_typename_param_k P , ss_typename_param_k T > inline void r_replace_copy_if_impl(RI ri, RO ro, P pred, T newVal, indirect_range_tag const&, indirect_range_tag const&) { ri.replace_copy_if(ro, pred, newVal); } template< ss_typename_param_k RI , ss_typename_param_k RO , ss_typename_param_k P , ss_typename_param_k T > inline void r_replace_copy_if(RI ri, RO ro, P pred, T newVal) { r_replace_copy_if_impl(ri, ro, pe, newVal, ri, ro); } #endif /* 0 */ //////////////////////////////////////////////////////////////////////////// // Unit-testing #ifdef STLSOFT_UNITTEST # include "./unittest/algorithms_unittest_.h" #endif /* STLSOFT_UNITTEST */ /* ////////////////////////////////////////////////////////////////////// */ #ifndef RANGELIB_NO_NAMESPACE # if defined(_STLSOFT_NO_NAMESPACE) || \ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) } // namespace rangelib # else } // namespace rangelib_project } // namespace stlsoft # endif /* _STLSOFT_NO_NAMESPACE */ #endif /* !RANGELIB_NO_NAMESPACE */ /* ////////////////////////////////////////////////////////////////////// */ #endif /* !RANGELIB_INCL_RANGELIB_HPP_ALGORITHMS */ /* ///////////////////////////// end of file //////////////////////////// */