You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1649 lines
40 KiB

/* /////////////////////////////////////////////////////////////////////////
* 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 <rangelib/rangelib.hpp>
#endif /* !RANGELIB_INCL_RANGELIB_HPP_RANGELIB */
#ifndef RANGELIB_INCL_RANGELIB_HPP_RANGE_CATEGORIES
# include <rangelib/range_categories.hpp>
#endif /* !RANGELIB_INCL_RANGELIB_HPP_RANGE_CATEGORIES */
#ifndef RANGELIB_INCL_RANGELIB_ERROR_HPP_EXCEPTIONS
# include <rangelib/error/exceptions.hpp>
#endif /* !RANGELIB_INCL_RANGELIB_ERROR_HPP_EXCEPTIONS */
#ifndef RANGELIB_INCL_RANGELIB_HPP_BASIC_INDIRECT_RANGE_ADAPTOR
# include <rangelib/basic_indirect_range_adaptor.hpp>
#endif /* !RANGELIB_INCL_RANGELIB_HPP_BASIC_INDIRECT_RANGE_ADAPTOR */
#ifndef STLSOFT_INCL_ALGORITHM
# define STLSOFT_INCL_ALGORITHM
# include <algorithm>
#endif /* !STLSOFT_INCL_ALGORITHM */
#ifndef STLSOFT_INCL_NUMERIC
# define STLSOFT_INCL_NUMERIC
# include <numeric>
#endif /* !STLSOFT_INCL_NUMERIC */
#ifdef STLSOFT_UNITTEST
# include <rangelib/integral_range.hpp>
# include <rangelib/sequence_range.hpp>
# include <iterator>
# include <list>
#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>(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>(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>(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>(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>(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>(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 <ss_typename_param_k R>
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 <ss_typename_param_k R>
inline ss_ptrdiff_t r_distance_1_impl(R r, iterable_range_tag const&)
{
return std::distance(r.begin(), r.end());
}
template <ss_typename_param_k R>
inline ss_ptrdiff_t r_distance_1_impl(R r, indirect_range_tag const&)
{
return r.distance();
}
template <ss_typename_param_k R>
inline ss_ptrdiff_t r_distance_1_impl(R r, basic_indirect_range_tag const&)
{
return indirect_range_adaptor<R>(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 <ss_typename_param_k R>
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>(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>(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>(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 <code><= r_distance(r)</code>
* \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>(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 <ss_typename_param_k R>
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 <ss_typename_param_k I>
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 <ss_typename_param_k R>
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 <ss_typename_param_k R>
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>(r).max_element();
}
template <ss_typename_param_k R>
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 <ss_typename_param_k R>
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>(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 <ss_typename_param_k R>
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 <ss_typename_param_k I>
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 <ss_typename_param_k R>
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 <ss_typename_param_k R>
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>(r).min_element();
}
template <ss_typename_param_k R>
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 <ss_typename_param_k R>
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>(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 //////////////////////////// */