blob: 1658458ee1854d8dddc602f70e84e8ea4e14b18d [file] [log] [blame]
//
// Copyright 2013 Francisco Jerez
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#ifndef CLOVER_UTIL_ALGORITHM_HPP
#define CLOVER_UTIL_ALGORITHM_HPP
#include <algorithm>
#include <stdexcept>
#include "util/range.hpp"
#include "util/functional.hpp"
namespace clover {
namespace detail {
template<typename R>
using preferred_reference_type = decltype(*std::declval<R>().begin());
}
///
/// Return the first element in a range.
///
template<typename R>
detail::preferred_reference_type<R>
head(R &&r) {
assert(!r.empty());
return r.front();
}
///
/// Return all elements in a range but the first.
///
template<typename R>
slice_range<R>
tail(R &&r) {
assert(!r.empty());
return { std::forward<R>(r), 1, r.size() };
}
///
/// Return the only element in a range.
///
template<typename R>
detail::preferred_reference_type<R>
unique(R &&r) {
if (r.size() != 1)
throw std::out_of_range("");
return r.front();
}
///
/// Combine a variable number of ranges element-wise in a single
/// range of tuples.
///
template<typename... Rs>
adaptor_range<zips, Rs...>
zip(Rs &&... rs) {
return map(zips(), std::forward<Rs>(rs)...);
}
///
/// Evaluate the elements of a range.
///
/// Useful because most of the range algorithms evaluate their
/// result lazily.
///
template<typename R>
void
eval(R &&r) {
for (auto i = r.begin(), e = r.end(); i != e; ++i)
*i;
}
///
/// Apply functor \a f element-wise on a variable number of ranges
/// \a rs.
///
/// The functor \a f should take as many arguments as ranges are
/// provided.
///
template<typename F, typename... Rs>
void
for_each(F &&f, Rs &&... rs) {
eval(map(std::forward<F>(f), std::forward<Rs>(rs)...));
}
///
/// Copy all elements from range \a r into an output container
/// starting from iterator \a i.
///
template<typename R, typename I>
void
copy(R &&r, I i) {
for (detail::preferred_reference_type<R> x : r)
*(i++) = x;
}
///
/// Reduce the elements of range \a r by applying functor \a f
/// element by element.
///
/// \a f should take an accumulator value (which is initialized to
/// \a a) and an element value as arguments, and return an updated
/// accumulator value.
///
/// \returns The final value of the accumulator.
///
template<typename F, typename A, typename R>
A
fold(F &&f, A a, R &&r) {
for (detail::preferred_reference_type<R> x : r)
a = f(a, x);
return a;
}
///
/// Return how many elements of range \a r are equal to \a x.
///
template<typename T, typename R>
typename std::remove_reference<R>::type::size_type
count(T &&x, R &&r) {
typename std::remove_reference<R>::type::size_type n = 0;
for (detail::preferred_reference_type<R> y : r) {
if (x == y)
n++;
}
return n;
}
///
/// Return the first element in range \a r for which predicate \a f
/// evaluates to true.
///
template<typename F, typename R>
detail::preferred_reference_type<R>
find(F &&f, R &&r) {
for (detail::preferred_reference_type<R> x : r) {
if (f(x))
return x;
}
throw std::out_of_range("");
}
///
/// Return true if the element-wise application of predicate \a f
/// on \a rs evaluates to true for all elements.
///
template<typename F, typename... Rs>
bool
all_of(F &&f, Rs &&... rs) {
for (auto b : map(f, rs...)) {
if (!b)
return false;
}
return true;
}
///
/// Return true if the element-wise application of predicate \a f
/// on \a rs evaluates to true for any element.
///
template<typename F, typename... Rs>
bool
any_of(F &&f, Rs &&... rs) {
for (auto b : map(f, rs...)) {
if (b)
return true;
}
return false;
}
///
/// Erase elements for which predicate \a f evaluates to true from
/// container \a r.
///
template<typename F, typename R>
void
erase_if(F &&f, R &&r) {
auto i = r.begin(), e = r.end();
for (auto j = r.begin(); j != e; ++j) {
if (!f(*j)) {
if (j != i)
*i = std::move(*j);
++i;
}
}
r.erase(i, e);
}
}
#endif