Вот мой набор дополнительных утилит, построенных на основе оболочки std-algo boost.range'ish, которые могут вам понадобиться для некоторых функций.(написать тривиально, это интересный материал)
#pragma once
/** @file
@brief Defines various utility classes/functions for handling ranges/function objects
in addition to bsRange (which is a ranged version of the \<algorithm\> header)
Items here uses a STL/boost-style naming due to their 'templatised' nature.
If template variable is R, anything matching range_concept can be used.
If template variable is C, it must be a container object (supporting C::erase())
*/
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/smart_ptr.hpp>
namespace boost
{
struct use_default;
template<class T>
class iterator_range;
#pragma warning(disable: 4348) // redeclaration of template default parameters (this clashes with fwd-decl in boost/transform_iterator.hpp)
template <
class UnaryFunction
, class Iterator
, class Reference = use_default
, class Value = use_default
>
class transform_iterator;
template <
class Iterator
, class Value = use_default
, class Category = use_default
, class Reference = use_default
, class difference = use_default
>
class indirect_iterator;
template<class T>
struct range_iterator;
template <
class Incrementable
, class CategoryOrTraversal = use_default
, class difference = use_default
>
class counting_iterator;
template <class Predicate, class Iterator>
class filter_iterator;
}
namespace orz
{
/// determines if any value that compares equal exists in container
template<class R, class T>
inline bool contains(const R& r, const T& v)
{
return std::find(boost::begin(r), boost::end(r), v) != boost::end(r);
}
/// determines if predicate evaluates to true for any value in container
template<class R, class F>
inline bool contains_if(const R& r, const F& f)
{
return std::find_if(boost::begin(r), boost::end(r), f) != boost::end(r);
}
/// insert elements in range r at end of container c
template<class R, class C>
inline void insert(C& c, const R& r)
{
c.insert(c.end(), boost::begin(r), boost::end(r));
}
/// copy elements that match predicate
template<class I, class O, class P>
inline void copy_if(I i, I end, O& o, const P& p)
{
for (; i != end; ++i) {
if (p(*i)) {
*o = *i;
++o;
}
}
}
/// copy elements that match predicate
template<class R, class O, class P>
inline void copy_if(R& r, O& o, const P& p)
{
copy_if(boost::begin(r), boost::end(r), o, p);
}
/// erases first element that compare equal
template<class C, class T>
inline bool erase_first(C& c, const T& v)
{
typename C::iterator end = boost::end(c);
typename C::iterator i = std::find(boost::begin(c), end, v);
return i != c.end() ? c.erase(i), true : false;
}
/// erases first elements that match predicate
template<class C, class F>
inline bool erase_first_if(C& c, const F& f)
{
typename C::iterator end = boost::end(c);
typename C::iterator i = std::find_if(boost::begin(c), end, f);
return i != end ? c.erase(i), true : false;
}
/// erase all elements (doesn't deallocate memory for std::vector)
template<class C>
inline void erase_all(C& c)
{
c.erase(c.begin(), c.end());
}
/// erase all elements that compare equal
template<typename C, typename T>
int erase(C& c, const T& value)
{
int n = 0;
for (boost::range_iterator<C>::type i = boost::begin(c); i != boost::end(c);) {
if (*i == value) {
i = c.erase(i);
++n;
} else {
++i;
}
}
return n;
}
/// erase all elements that match predicate
template<typename C, typename F>
int erase_if(C& c, const F& f)
{
int n = 0;
for (boost::range_iterator<C>::type i = boost::begin(c); i != boost::end(c);) {
if (f(*i)) {
i = c.erase(i);
++n;
} else {
++i;
}
}
return n;
}
/// erases all consecutive duplicates from container (sort container first to get all)
template<class C>
inline int erase_duplicates(C& c)
{
boost::range_iterator<C>::type i = std::unique(c.begin(), c.end());
typename C::size_type n = std::distance(i, c.end());
c.erase(i, c.end());
return n;
}
/// erases all consecutive duplicates, according to predicate, from container (sort container first to get all)
template<class C, class F>
inline int erase_duplicates_if(C& c, const F& f)
{
boost::range_iterator<C>::type i = std::unique(c.begin(), c.end(), f);
typename C::size_type n = std::distance(i, c.end());
c.erase(i, c.end());
return n;
}
/// fill but for the second value in each pair in range
template<typename R, typename V>
inline void fill_second(R& r, const V& v)
{
boost::range_iterator<R>::type i(boost::begin(r)), end(boost::end(r));
for (; i != end; ++i) {
i->second = v;
}
}
/// applying function to corresponding pair through both ranges, min(r1.size(), r2,size()) applications
template<typename R1, typename R2, typename F>
void for_each2(R1& r1, R2& r2, const F& f)
{
boost::range_iterator<R1>::type i(boost::begin(r1)), i_end(boost::end(r1));
boost::range_iterator<R2>::type j(boost::begin(r2)), j_end(boost::end(r2));
for(;i != i_end && j != j_end; ++i, ++j) {
f(*i, *j);
}
}
/// applying function to corresponding pair through both ranges, min(r1.size(), r2,size()) applications
template<typename R1, typename R2, typename R3, typename F>
void for_each3(R1& r1, R2& r2, R3& r3, const F& f)
{
boost::range_iterator<R1>::type i(boost::begin(r1)), i_end(boost::end(r1));
boost::range_iterator<R2>::type j(boost::begin(r2)), j_end(boost::end(r2));
boost::range_iterator<R3>::type k(boost::begin(r3)), k_end(boost::end(r3));
for(;i != i_end && j != j_end && k != k_end; ++i, ++j, ++k) {
f(*i, *j, *k);
}
}
/// applying function to each possible permutation of objects, r1.size() * r2.size() applications
template<class R1, class R2, class F>
void for_each_permutation(R1 & r1, R2& r2, const F& f)
{
typedef boost::range_iterator<R1>::type R1_iterator;
typedef boost::range_iterator<R2>::type R2_iterator;
R1_iterator end_1 = boost::end(r1);
R2_iterator begin_2 = boost::begin(r2);
R2_iterator end_2 = boost::end(r2);
for(R1_iterator i = boost::begin(r1); i != end_1; ++i) {
for(R2_iterator j = begin_2; j != end_2; ++j) {
f(*i, *j);
}
}
}
template <class R>
inline boost::iterator_range<boost::indirect_iterator<typename boost::range_iterator<R>::type > >
make_indirect_range(R& r)
{
return boost::iterator_range<boost::indirect_iterator<typename boost::range_iterator<R>::type > > (r);
}
template <class R, class F>
inline boost::iterator_range<boost::transform_iterator<F, typename boost::range_iterator<R>::type> >
make_transform_range(R& r, const F& f)
{
return boost::iterator_range<boost::transform_iterator<F, typename boost::range_iterator<R>::type> >(
boost::make_transform_iterator(boost::begin(r), f),
boost::make_transform_iterator(boost::end(r), f));
}
template <class T>
inline boost::iterator_range<boost::counting_iterator<T> >
make_counting_range(T begin, T end)
{
return boost::iterator_range<boost::counting_iterator<T> >(
boost::counting_iterator<T>(begin), boost::counting_iterator<T>(end));
}
template <class R, class F>
inline boost::iterator_range<boost::filter_iterator<F, typename boost::range_iterator<R>::type> >
make_filter_range(R& r, const F& f)
{
return boost::iterator_range<boost::filter_iterator<F, typename boost::range_iterator<R>::type> >(
boost::make_filter_iterator(f, boost::begin(r), boost::end(r)),
boost::make_filter_iterator(f, boost::end(r), boost::end(r)));
}
namespace detail {
template<class T>
T* get_pointer(T& p) {
return &p;
}
}
/// compare member function/variable equal to value. Create using @ref mem_eq() to avoid specfying types
template<class P, class V>
struct mem_eq_type
{
mem_eq_type(const P& p, const V& v) : m_p(p), m_v(v) { }
template<class T>
bool operator()(const T& a) const {
using boost::get_pointer;
using orz::detail::get_pointer;
return (get_pointer(a)->*m_p) == m_v;
}
P m_p;
V m_v;
};
template<class P, class V>
mem_eq_type<P,V> mem_eq(const P& p, const V& v)
{
return mem_eq_type<P,V>(p, v);
}
/// helper macro to define function objects that compare member variables of a class
#define ORZ_COMPARE_MEMBER(NAME, OP) \
template <class P> \
struct NAME##_type \
{ \
NAME##_type(const P&p) : m_p(p) {} \
template<class T> \
bool operator()(const T& a, const T& b) const { \
return (a.*m_p) OP (b.*m_p); \
} \
P m_p; \
}; \
template <class P> \
NAME##_type<P> NAME(const P& p) { return NAME##_type<P>(p); }
#define ORZ_COMPARE_MEMBER_FN(NAME, OP) \
template <class P> \
struct NAME##_type \
{ \
NAME##_type(const P&p) : m_p(p) {} \
template<class T> \
bool operator()(const T& a, const T& b) const { \
return (a.*m_p)() OP (b.*m_p)(); \
} \
P m_p; \
}; \
template <class P> \
NAME##_type<P> NAME(const P& p) { return NAME##_type<P>(p); }
/// helper macro to wrap range functions as function objects (value return)
#define ORZ_RANGE_WRAP_VALUE_2(FUNC, RESULT) \
struct FUNC##_ \
{ \
typedef RESULT result_type; \
template<typename R, typename F> \
inline RESULT operator() (R& r, const F& f) const \
{ \
return FUNC(r, f); \
} \
};
/// helper macro to wrap range functions as function objects (void return)
#define ORZ_RANGE_WRAP_VOID_2(FUNC) \
struct FUNC##_ \
{ \
typedef void result_type; \
template<typename R, typename F> \
inline void operator() (R& r, const F& f) const \
{ \
FUNC(r, f); \
} \
};
/// helper macro to wrap range functions as function objects (void return, one argument)
#define ORZ_RANGE_WRAP_VOID_1(FUNC) \
struct FUNC##_ \
{ \
typedef void result_type; \
template<typename R> \
inline void operator() (R& r) const \
{ \
FUNC(r); \
} \
};
ORZ_RANGE_WRAP_VOID_2(for_each);
ORZ_RANGE_WRAP_VOID_1(erase_all);
ORZ_RANGE_WRAP_VALUE_2(contains, bool);
ORZ_RANGE_WRAP_VALUE_2(contains_if, bool);
ORZ_COMPARE_MEMBER(mem_equal, ==)
ORZ_COMPARE_MEMBER(mem_not_equal, !=)
ORZ_COMPARE_MEMBER(mem_less, <)
ORZ_COMPARE_MEMBER(mem_greater, >)
ORZ_COMPARE_MEMBER(mem_lessequal, <=)
ORZ_COMPARE_MEMBER(mem_greaterequal, >=)
ORZ_COMPARE_MEMBER_FN(mem_equal_fn, ==)
ORZ_COMPARE_MEMBER_FN(mem_not_equal_fn, !=)
ORZ_COMPARE_MEMBER_FN(mem_less_fn, <)
ORZ_COMPARE_MEMBER_FN(mem_greater_fn, >)
ORZ_COMPARE_MEMBER_FN(mem_lessequal_fn, <=)
ORZ_COMPARE_MEMBER_FN(mem_greaterequal_fn, >=)
#undef ORZ_COMPARE_MEMBER
#undef ORZ_RANGE_WRAP_VALUE_2
#undef ORZ_RANGE_WRAP_VOID_1
#undef ORZ_RANGE_WRAP_VOID_2
}