824 lines
25 KiB
C++
824 lines
25 KiB
C++
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <initializer_list>
|
|
#include <numeric>
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
namespace waybar::util {
|
|
|
|
/// Joins a sequence of strings, separating them using `js`
|
|
template<class StrIterator> // Models InputIterator<std::string>
|
|
std::string join_strings(StrIterator b, StrIterator e, std::string_view js = ", ")
|
|
{
|
|
std::string result;
|
|
std::for_each(b, e, [&](auto&& s) {
|
|
if (!result.empty()) {
|
|
result.append(js);
|
|
}
|
|
result.append(s);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
inline const char* nonull(const char* str) {
|
|
if (str == nullptr) return "";
|
|
return str;
|
|
};
|
|
|
|
inline bool iequals(std::string_view a, std::string_view b)
|
|
{
|
|
return std::equal(a.begin(), a.end(), b.begin(), b.end(),
|
|
[](char a, char b) { return tolower(a) == tolower(b); });
|
|
}
|
|
|
|
inline bool starts_with(std::string_view prefix, std::string_view a)
|
|
{
|
|
return a.compare(0, prefix.size(), prefix) == 0;
|
|
}
|
|
|
|
inline bool ends_with(std::string_view prefix, std::string_view a)
|
|
{
|
|
return a.compare(a.size() - prefix.size(), prefix.size(), prefix) == 0;
|
|
}
|
|
|
|
/// Return a closure which compares the adress any reference to T to the address of t
|
|
template<typename T>
|
|
constexpr auto addr_eq(T&& t) {
|
|
return [&t] (auto&& t2) {
|
|
return &t == &t2;
|
|
};
|
|
}
|
|
|
|
template<typename T>
|
|
bool erase_this(std::vector<T>& cont, T* el)
|
|
{
|
|
if (el < cont.data() && el >= cont.data() + cont.size()) return false;
|
|
cont.erase(cont.begin() + (el - cont.data()));
|
|
return true;
|
|
}
|
|
|
|
template<typename T>
|
|
bool erase_this(std::vector<T>& cont, T& el)
|
|
{
|
|
return erase_this(cont, &el);
|
|
}
|
|
|
|
namespace detail {
|
|
template<class Func, int... ns>
|
|
constexpr auto generate_array_impl(std::integer_sequence<int, ns...>&&, Func&& gen)
|
|
{
|
|
return std::array<std::decay_t<decltype(std::invoke(gen, std::declval<int>()))>,
|
|
sizeof...(ns)>{{std::invoke(gen, ns)...}};
|
|
}
|
|
} // namespace detail
|
|
|
|
template<int n, class Func>
|
|
constexpr auto generate_array(Func&& gen)
|
|
{
|
|
auto intseq = std::make_integer_sequence<int, n>();
|
|
return detail::generate_array_impl(std::move(intseq), std::forward<Func>(gen));
|
|
}
|
|
|
|
namespace view {
|
|
|
|
namespace detail {
|
|
template<typename T>
|
|
using store_or_ref_t = std::conditional_t<std::is_rvalue_reference_v<T>, std::decay_t<T>, T&>;
|
|
}
|
|
|
|
template<typename Cont>
|
|
struct reverse {
|
|
|
|
reverse(Cont&& cont) noexcept : _container(std::forward<Cont>(cont)) {}
|
|
|
|
auto begin()
|
|
{
|
|
return std::rbegin(_container);
|
|
}
|
|
|
|
auto end()
|
|
{
|
|
return std::rend(_container);
|
|
}
|
|
|
|
auto begin() const
|
|
{
|
|
return std::rbegin(_container);
|
|
}
|
|
|
|
auto end() const
|
|
{
|
|
return std::rend(_container);
|
|
}
|
|
|
|
auto cbegin() const
|
|
{
|
|
return std::crbegin(_container);
|
|
}
|
|
|
|
auto cend() const
|
|
{
|
|
return std::crend(_container);
|
|
}
|
|
|
|
detail::store_or_ref_t<Cont&&> _container;
|
|
};
|
|
|
|
template<typename ContRef>
|
|
reverse(ContRef&& cont) -> reverse<ContRef&&>;
|
|
|
|
template<typename Cont>
|
|
struct constant {
|
|
constant(Cont&& cont) noexcept : _container(std::forward<Cont>(cont)){};
|
|
|
|
auto begin() const
|
|
{
|
|
return std::cbegin(_container);
|
|
}
|
|
|
|
auto end() const
|
|
{
|
|
return std::cend(_container);
|
|
}
|
|
|
|
auto cbegin() const
|
|
{
|
|
return std::cbegin(_container);
|
|
}
|
|
|
|
auto cend() const
|
|
{
|
|
return std::cend(_container);
|
|
}
|
|
|
|
detail::store_or_ref_t<Cont&&> _container;
|
|
};
|
|
|
|
template<typename ContRef>
|
|
constant(ContRef&& cont) -> constant<ContRef&&>;
|
|
|
|
} // namespace view
|
|
|
|
|
|
/*
|
|
* Range algorithms
|
|
*/
|
|
|
|
template<typename InputIt, typename Size, typename F>
|
|
constexpr InputIt for_each_n(InputIt&& first, Size n, F&& f)
|
|
{
|
|
for (Size i = 0; i < n; ++first, ++i) {
|
|
std::invoke(f, *first);
|
|
}
|
|
return first;
|
|
}
|
|
|
|
/// `for_each` with access to an index value. Function called as `f(*it, i)`
|
|
///
|
|
/// For each item in range `[first, last)`, invoke `f` with args
|
|
/// `*iter, i` where `iter` is the current iterator, and `i` is
|
|
/// an incrementing value, starting at zero. Use this instead of
|
|
/// raw indexed loops wherever possible.
|
|
///
|
|
/// \param first Input iterator to the begining of the range
|
|
/// \param last Input iterator to the end of the range
|
|
/// \param f Must be invocable with arguments `value_type`, `std::size_t`
|
|
/// \returns The number of iterations performed
|
|
template<typename InputIt, typename F>
|
|
constexpr std::size_t indexed_for(InputIt&& first, InputIt&& last, F&& f)
|
|
{
|
|
std::size_t i = 0;
|
|
std::for_each(std::forward<InputIt>(first), std::forward<InputIt>(last), [&](auto&& a) {
|
|
std::invoke(f, a, i);
|
|
i++;
|
|
});
|
|
return i;
|
|
}
|
|
|
|
template<typename Rng, typename F>
|
|
constexpr std::size_t indexed_for(Rng&& rng, F&& f)
|
|
{
|
|
return indexed_for(std::begin(rng), std::end(rng), std::forward<F>(f));
|
|
}
|
|
|
|
|
|
/// `for_each_n` with access to an index value. Function called as `f(*it, i)`
|
|
///
|
|
/// for `n` iterations, invoke `f` with args `*iter, i`
|
|
/// where `iter` is the current iterator starting with `first`,
|
|
/// and `i` is an incrementing value, starting at zero.
|
|
/// Use this instead of raw indexed loops wherever possible.
|
|
///
|
|
/// \param first Input iterator to the begining of the range
|
|
/// \param n Number of iterations to go through
|
|
/// \param f Must be invocable with arguments `value_type`, `std::size_t`
|
|
/// \returns An iterator one past the last one visited
|
|
template<class InputIt, class Size, class F>
|
|
constexpr InputIt indexed_for_n(InputIt first, Size n, F&& f)
|
|
{
|
|
for (Size i = 0; i < n; ++first, ++i) {
|
|
std::invoke(f, *first, i);
|
|
}
|
|
return first;
|
|
}
|
|
|
|
template<class Rng, class Size, class F>
|
|
constexpr std::size_t indexed_for_n(Rng&& rng, Size n, F&& f)
|
|
{
|
|
return indexed_for_n(std::begin(rng), std::end(rng), n, std::forward<F>(f));
|
|
}
|
|
|
|
template<typename Iter1, typename Iter2, typename F>
|
|
constexpr void for_both(Iter1&& f1, Iter1&& l1, Iter2&& f2, Iter2&& l2, F&& f)
|
|
{
|
|
Iter1 i1 = std::forward<Iter1>(f1);
|
|
Iter2 i2 = std::forward<Iter2>(f2);
|
|
for (; i1 != l1 && i2 != l2; i1++, i2++) {
|
|
std::invoke(f, *i1, *i2);
|
|
}
|
|
}
|
|
|
|
template<typename Rng1, typename Rng2, typename F>
|
|
constexpr void for_both(Rng1&& r1, Rng2&& r2, F&& f)
|
|
{
|
|
for_both(std::begin(r1), std::end(r1), std::begin(r2), std::end(r2), std::forward<F>(f));
|
|
}
|
|
|
|
/*
|
|
* Range based standard algorithms
|
|
*
|
|
* Thanks, chris from SO!
|
|
*/
|
|
|
|
template<typename Cont, typename T>
|
|
constexpr auto accumulate(Cont&& cont, T&& init)
|
|
{
|
|
// TODO C++20: std::accumulate is constexpr
|
|
using std::begin, std::end;
|
|
auto first = begin(cont);
|
|
auto last = end(cont);
|
|
for (; first != last; ++first) init = init + *first;
|
|
return init;
|
|
}
|
|
|
|
template<typename Cont, typename T, typename BinaryOperation>
|
|
constexpr auto accumulate(Cont&& cont, T&& init, BinaryOperation&& op)
|
|
{
|
|
// TODO C++20: std::accumulate is constexpr
|
|
using std::begin, std::end;
|
|
auto first = begin(cont);
|
|
auto last = end(cont);
|
|
for (; first != last; ++first) init = op(init, *first);
|
|
return init;
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator>
|
|
decltype(auto) adjacent_difference(Cont&& cont, OutputIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::adjacent_difference(begin(cont), end(cont), std::forward<OutputIterator>(first));
|
|
}
|
|
|
|
template<typename Cont>
|
|
decltype(auto) prev_permutation(Cont&& cont)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::prev_permutation(begin(cont), end(cont));
|
|
}
|
|
|
|
template<typename Cont, typename Compare>
|
|
decltype(auto) prev_permutation(Cont&& cont, Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::prev_permutation(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont>
|
|
decltype(auto) push_heap(Cont&& cont)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::push_heap(begin(cont), end(cont));
|
|
}
|
|
|
|
template<typename Cont, typename Compare>
|
|
decltype(auto) push_heap(Cont&& cont, Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::push_heap(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont, typename T>
|
|
decltype(auto) remove(Cont&& cont, T&& value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::remove(begin(cont), end(cont), std::forward<T>(value));
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator, typename T>
|
|
decltype(auto) remove_copy(Cont&& cont, OutputIterator&& first, T&& value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::remove_copy(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
std::forward<T>(value));
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator, typename UnaryPredicate>
|
|
decltype(auto) remove_copy_if(Cont&& cont, OutputIterator&& first, UnaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::remove_copy_if(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
std::forward<UnaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont, typename UnaryPredicate>
|
|
decltype(auto) remove_if(Cont&& cont, UnaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::remove_if(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont, typename T, typename T2>
|
|
decltype(auto) replace(Cont&& cont, T&& old_value, T2&& new_value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::replace(begin(cont), end(cont), std::forward<T>(old_value),
|
|
std::forward<T2>(new_value));
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator, typename T, typename T2>
|
|
decltype(auto) replace_copy(Cont&& cont, OutputIterator&& first, T&& old_value, T2&& new_value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::replace_copy(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
std::forward<T>(old_value), std::forward<T2>(old_value));
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator, typename UnaryPredicate, typename T>
|
|
decltype(auto) replace_copy_if(Cont&& cont,
|
|
OutputIterator&& first,
|
|
UnaryPredicate&& p,
|
|
T&& new_value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::replace_copy(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
std::forward<UnaryPredicate>(p), std::forward<T>(new_value));
|
|
}
|
|
|
|
template<typename Cont, typename UnaryPredicate, typename T>
|
|
decltype(auto) replace_if(Cont&& cont, UnaryPredicate&& p, T&& new_value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::replace_if(begin(cont), end(cont), std::forward<UnaryPredicate>(p),
|
|
std::forward<T>(new_value));
|
|
}
|
|
|
|
template<typename Cont>
|
|
decltype(auto) reverse(Cont&& cont)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::reverse(begin(cont), end(cont));
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator>
|
|
decltype(auto) reverse_copy(Cont&& cont, OutputIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::reverse_copy(begin(cont), end(cont), std::forward<OutputIterator>(first));
|
|
}
|
|
|
|
template<typename Cont, typename ForwardIterator>
|
|
decltype(auto) rotate(Cont&& cont, ForwardIterator&& new_first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::rotate(begin(cont), std::forward<ForwardIterator>(new_first), end(cont));
|
|
}
|
|
|
|
template<typename Cont, typename ForwardIterator, typename OutputIterator>
|
|
decltype(auto) rotate_copy(Cont&& cont, ForwardIterator&& new_first, OutputIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::rotate_copy(begin(cont), std::forward<ForwardIterator>(new_first), end(cont),
|
|
std::forward<OutputIterator>(first));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2>
|
|
decltype(auto) search(Cont&& cont, Cont2&& cont2)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::search(begin(cont), end(cont), begin(cont2), end(cont2));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename BinaryPredicate>
|
|
decltype(auto) search(Cont&& cont, Cont2&& cont2, BinaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::search(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
std::forward<BinaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont, typename Size, typename T>
|
|
decltype(auto) search_n(Cont&& cont, Size count, T&& value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::search_n(begin(cont), end(cont), count, std::forward<T>(value));
|
|
}
|
|
|
|
template<typename Cont, typename Size, typename T, typename BinaryPredicate>
|
|
decltype(auto) search_n(Cont&& cont, Size count, T&& value, BinaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::search_n(begin(cont), end(cont), count, std::forward<T>(value),
|
|
std::forward<BinaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename OutputIterator>
|
|
decltype(auto) set_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::set_difference(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
std::forward<OutputIterator>(first));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename OutputIterator, typename Compare>
|
|
decltype(auto) set_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first, Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::set_difference(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
std::forward<OutputIterator>(first), std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename OutputIterator>
|
|
decltype(auto) set_intersection(Cont&& cont, Cont2&& cont2, OutputIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::set_intersection(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
std::forward<OutputIterator>(first));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename OutputIterator, typename Compare>
|
|
decltype(auto) set_intersection(Cont&& cont,
|
|
Cont2&& cont2,
|
|
OutputIterator&& first,
|
|
Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::set_intersection(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
std::forward<OutputIterator>(first), std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename OutputIterator>
|
|
decltype(auto) set_symmetric_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::set_symmetric_difference(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
std::forward<OutputIterator>(first));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename OutputIterator, typename Compare>
|
|
decltype(auto) set_symmetric_difference(Cont&& cont,
|
|
Cont2&& cont2,
|
|
OutputIterator&& first,
|
|
Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::set_symmetric_difference(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
std::forward<OutputIterator>(first),
|
|
std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename OutputIterator>
|
|
decltype(auto) set_union(Cont&& cont, Cont2&& cont2, OutputIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::set_union(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
std::forward<OutputIterator>(first));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename OutputIterator, typename Compare>
|
|
decltype(auto) set_union(Cont&& cont, Cont2&& cont2, OutputIterator&& first, Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::set_union(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
std::forward<OutputIterator>(first), std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont, typename UniformRandomNumberGenerator>
|
|
decltype(auto) shuffle(Cont&& cont, UniformRandomNumberGenerator&& g)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::shuffle(begin(cont), end(cont), std::forward<UniformRandomNumberGenerator>(g));
|
|
}
|
|
|
|
template<typename Cont>
|
|
decltype(auto) sort(Cont&& cont)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::sort(begin(cont), end(cont));
|
|
}
|
|
|
|
template<typename Cont, typename Compare>
|
|
decltype(auto) sort(Cont&& cont, Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::sort(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont>
|
|
decltype(auto) sort_heap(Cont&& cont)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::sort_heap(begin(cont), end(cont));
|
|
}
|
|
|
|
template<typename Cont, typename Compare>
|
|
decltype(auto) sort_heap(Cont&& cont, Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::sort_heap(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont, typename UnaryPredicate>
|
|
decltype(auto) stable_partition(Cont&& cont, UnaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::stable_partition(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont>
|
|
decltype(auto) stable_sort(Cont&& cont)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::stable_sort(begin(cont), end(cont));
|
|
}
|
|
|
|
template<typename Cont, typename Compare>
|
|
decltype(auto) stable_sort(Cont&& cont, Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::stable_sort(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont, typename ForwardIterator>
|
|
decltype(auto) swap_ranges(Cont&& cont, ForwardIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::swap_ranges(begin(cont), end(cont), std::forward<ForwardIterator>(first));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename F>
|
|
auto transform(Cont&& cont, Cont2&& cont2, F&& f) -> decltype(begin(cont2))
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::transform(begin(cont), end(cont), begin(cont2), std::forward<F>(f));
|
|
}
|
|
|
|
template<typename Cont, typename Iter, typename F>
|
|
decltype(auto) transform(Cont&& cont, Iter&& iter, F&& f)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::transform(begin(cont), end(cont), std::forward<Iter>(iter), std::forward<F>(f));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename Cont3, typename BinaryPredicate>
|
|
auto transform(Cont&& cont, Cont2&& cont2, Cont3&& cont3, BinaryPredicate&& f)
|
|
-> decltype(begin(cont2), begin(cont3))
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::transform(begin(cont), end(cont), begin(cont2), begin(cont3),
|
|
std::forward<BinaryPredicate>(f));
|
|
}
|
|
|
|
template<typename Cont, typename InputIterator, typename Cont3, typename BinaryPredicate>
|
|
auto transform(Cont&& cont, InputIterator&& iter, Cont3&& cont3, BinaryPredicate&& f)
|
|
-> decltype(begin(cont), begin(cont3))
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::transform(begin(cont), end(cont), std::forward<InputIterator>(iter), begin(cont3),
|
|
std::forward<BinaryPredicate>(f));
|
|
}
|
|
|
|
template<typename Cont, typename Cont2, typename InputIterator, typename BinaryPredicate>
|
|
auto transform(Cont&& cont, Cont2&& cont2, InputIterator&& iter, BinaryPredicate&& f)
|
|
-> decltype(begin(cont), begin(cont2), iter)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::transform(begin(cont), end(cont), begin(cont2), std::forward<InputIterator>(iter),
|
|
std::forward<BinaryPredicate>(f));
|
|
}
|
|
|
|
template<typename Cont, typename InputIterator, typename OutputIterator, typename BinaryOperation>
|
|
decltype(auto) transform(Cont&& cont,
|
|
InputIterator&& firstIn,
|
|
OutputIterator&& firstOut,
|
|
BinaryOperation&& op)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::transform(begin(cont), end(cont), std::forward<InputIterator>(firstIn),
|
|
std::forward<OutputIterator>(firstOut),
|
|
std::forward<BinaryOperation>(op));
|
|
}
|
|
|
|
template<typename Cont>
|
|
decltype(auto) unique(Cont&& cont)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::unique(begin(cont), end(cont));
|
|
}
|
|
|
|
template<typename Cont, typename BinaryPredicate>
|
|
decltype(auto) unique(Cont&& cont, BinaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::unique(begin(cont), end(cont), std::forward<BinaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator>
|
|
decltype(auto) unique_copy(Cont&& cont, OutputIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::unique_copy(begin(cont), end(cont), std::forward<OutputIterator>(first));
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator, typename BinaryPredicate>
|
|
decltype(auto) unique_copy(Cont&& cont, OutputIterator&& first, BinaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::unique_copy(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
std::forward<BinaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont, typename T>
|
|
decltype(auto) upper_bound(Cont&& cont, T&& value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::upper_bound(begin(cont), end(cont), std::forward<T>(value));
|
|
}
|
|
|
|
template<typename Cont, typename T, typename Compare>
|
|
decltype(auto) upper_bound(Cont&& cont, T&& value, Compare&& comp)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::upper_bound(begin(cont), end(cont), std::forward<T>(value),
|
|
std::forward<Compare>(comp));
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator>
|
|
decltype(auto) copy(Cont&& cont, OutputIterator&& first)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::copy(begin(cont), end(cont), std::forward<OutputIterator>(first));
|
|
}
|
|
|
|
template<typename Cont, typename OutputIterator, typename UnaryPredicate>
|
|
decltype(auto) copy_if(Cont&& cont, OutputIterator&& first, UnaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::copy_if(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
std::forward<UnaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont, typename T>
|
|
decltype(auto) fill(Cont&& cont, T&& value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::fill(begin(cont), end(cont), std::forward<T>(value));
|
|
}
|
|
|
|
template<typename Cont, typename T>
|
|
decltype(auto) fill_n(Cont&& cont, std::size_t n, T&& value)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::fill_n(begin(cont), n, std::forward<T>(value));
|
|
}
|
|
|
|
template<typename Cont, typename UnaryPredicate>
|
|
decltype(auto) any_of(Cont&& cont, UnaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::any_of(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont, typename UnaryPredicate>
|
|
decltype(auto) all_of(Cont&& cont, UnaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::all_of(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont, typename UnaryPredicate>
|
|
decltype(auto) none_of(Cont&& cont, UnaryPredicate&& p)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::none_of(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
}
|
|
|
|
template<typename Cont>
|
|
decltype(auto) max_element(Cont&& cont)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::max_element(begin(cont), end(cont));
|
|
}
|
|
|
|
template<typename Cont>
|
|
decltype(auto) min_element(Cont&& cont)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::min_element(begin(cont), end(cont));
|
|
}
|
|
|
|
template<typename Cont, typename Compare>
|
|
decltype(auto) min_element(Cont&& cont, Compare&& f)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::min_element(begin(cont), end(cont), std::forward<Compare>(f));
|
|
}
|
|
|
|
template<typename Cont, typename Compare>
|
|
decltype(auto) max_element(Cont&& cont, Compare&& f)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::max_element(begin(cont), end(cont), std::forward<Compare>(f));
|
|
}
|
|
|
|
template<typename Cont, typename T>
|
|
decltype(auto) find(Cont&& cont, T&& t)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::find(begin(cont), end(cont), std::forward<T>(t));
|
|
}
|
|
|
|
template<typename Cont, typename UnaryPredicate>
|
|
decltype(auto) find_if(Cont&& cont, UnaryPredicate&& f)
|
|
{
|
|
using std::begin;
|
|
using std::end;
|
|
return std::find_if(begin(cont), end(cont), std::forward<UnaryPredicate>(f));
|
|
}
|
|
|
|
} // namespace waybar::util
|