8#include <initializer_list>
22 template<
typename ...Args>
34template<
typename ITER,
typename VAL>
35[[nodiscard]]
constexpr bool contains(ITER first, ITER last,
const VAL& val)
38 while (first != last) {
39 if (*first == val)
return true;
44template<
typename RANGE,
typename VAL>
45[[nodiscard]]
constexpr bool contains(
const RANGE& range,
const VAL& val)
47 return contains(std::begin(range), std::end(range), val);
50template<
typename ITER,
typename VAL,
typename Proj>
51[[nodiscard]]
bool contains(ITER first, ITER last,
const VAL& val, Proj proj)
54 while (first != last) {
55 if (std::invoke(proj, *first) == val)
return true;
60template<
typename RANGE,
typename VAL,
typename Proj>
61[[nodiscard]]
bool contains(
const RANGE& range,
const VAL& val, Proj proj)
63 return contains(std::begin(range), std::end(range), val, proj);
74template<
typename ITER,
typename VAL,
typename Proj = std::
identity>
75[[nodiscard]] ITER
find_unguarded(ITER first, ITER last,
const VAL& val, Proj proj = {})
78 [&](
const auto& e) {
return std::invoke(proj, e) == val; });
80template<
typename RANGE,
typename VAL,
typename Proj = std::
identity>
81[[nodiscard]]
auto find_unguarded(RANGE& range,
const VAL& val, Proj proj = {})
83 return find_unguarded(std::begin(range), std::end(range), val, proj);
90template<
typename ITER,
typename PRED>
95 assert(first != last);
96 if (pred(*first))
return first;
100template<
typename RANGE,
typename PRED>
111template<
typename RANGE,
typename VAL,
typename Proj = std::
identity>
114 auto it =
find_unguarded(std::rbegin(range), std::rend(range), val, proj);
119template<
typename RANGE,
typename PRED>
136template<
typename VECTOR>
149 if (&*it != &v.back()) {
150 *it = std::move(v.back());
171template<
typename ForwardIt,
typename OutputIt,
typename UnaryPredicate>
173 ForwardIt first, ForwardIt last, OutputIt out_true, UnaryPredicate p)
175 first = std::find_if(first, last, p);
176 auto out_false = first;
179 while (first != last) {
181l_true: *out_true++ = std::move(*first++);
183 *out_false++ = std::move(*first++);
187 return std::pair(out_true, out_false);
190template<
typename ForwardRange,
typename OutputIt,
typename UnaryPredicate>
198template<
typename ForwardRange,
typename UnaryOperation>
201 return std::transform(std::begin(range), std::end(range), std::begin(range), op);
207template<
typename InputIterator,
typename Proj = std::
identity>
208[[nodiscard]]
auto min_value(InputIterator first, InputIterator last, Proj proj = {})
210 assert(first != last);
211 auto result = std::invoke(proj, *first++);
212 while (first != last) {
213 result = std::min(result, std::invoke(proj, *first++));
218template<
typename InputRange,
typename Proj = std::
identity>
219[[nodiscard]]
auto min_value(InputRange&& range, Proj proj = {})
221 return min_value(std::begin(range), std::end(range), proj);
226template<
typename InputIterator,
typename Proj = std::
identity>
227[[nodiscard]]
auto max_value(InputIterator first, InputIterator last, Proj proj = {})
229 assert(first != last);
230 auto result = std::invoke(proj, *first++);
231 while (first != last) {
232 result = std::max(result, std::invoke(proj, *first++));
237template<
typename InputRange,
typename Proj = std::
identity>
238[[nodiscard]]
auto max_value(InputRange&& range, Proj proj = {})
240 return max_value(std::begin(range), std::end(range), proj);
247template<
typename InputRange,
typename Proj = std::
identity>
248[[nodiscard]]
constexpr auto sum(InputRange&& range, Proj proj = {})
250 using Iter =
decltype(std::begin(range));
251 using VT =
typename std::iterator_traits<Iter>::value_type;
252 using RT =
decltype(std::invoke(proj, std::declval<VT>()));
254 auto first = std::begin(range);
255 auto last = std::end(range);
257 while (first != last) {
258 init = std::move(init) + std::invoke(proj, *first++);
265 template<
typename T,
typename Iterator>
267 std::is_same_v<T, void>,
268 typename std::iterator_traits<Iterator>::value_type,
277template<
typename T =
void,
typename Range>
281 return {std::begin(range), std::end(range)};
295template<
typename... Ranges>
298 return (0 + ... + std::distance(std::begin(
ranges), std::end(
ranges)));
301template<
typename Result>
307template<
typename Result,
typename Range,
typename... Tail>
308void append(Result& x, Range&& y, Tail&&... tail)
317 x.emplace_back(std::forward<
decltype(e)>(e));
320 x.insert(std::end(x), std::begin(y), std::end(y));
328template<
typename Result,
typename T2,
typename... Tail>
329void append(Result& x, std::vector<T2>&& y, Tail&&... tail)
331 x.insert(std::end(x),
332 std::move_iterator(std::begin(y)),
333 std::move_iterator(std::end(y)));
340template<
typename T,
typename... Tail>
341void append(std::vector<T>& v, Tail&&... tail)
344 auto current = v.size();
345 if (
auto required = current + extra;
346 v.capacity() < required) {
347 v.reserve(current + std::max(current, extra));
356void append(std::vector<T>& v, std::vector<T>&& range)
359 v = std::move(range);
361 v.insert(std::end(v),
362 std::move_iterator(std::begin(range)),
363 std::move_iterator(std::end(range)));
368void append(std::vector<T>& x, std::initializer_list<T> list)
370 x.insert(x.end(), list);
374template<
typename T = void,
typename Range,
typename... Tail>
375[[nodiscard]]
auto concat(
const Range& range, Tail&&... tail)
378 std::vector<T2> result;
379 append(result, range, std::forward<Tail>(tail)...);
383template<
typename T,
typename... Tail>
384[[nodiscard]] std::vector<T>
concat(std::vector<T>&& v, Tail&&... tail)
386 append(v, std::forward<Tail>(tail)...);
392template<
typename T,
size_t X,
size_t Y>
393constexpr auto concatArray(
const std::array<T, X>& x,
const std::array<T, Y>& y)
395 std::array<T, X + Y> result = {};
398 for (
size_t i = 0; i < X; ++i) result[0 + i] = x[i];
399 for (
size_t i = 0; i < Y; ++i) result[X + i] = y[i];
403template<
typename T,
size_t X,
size_t Y,
size_t Z>
405 const std::array<T, Y>& y,
406 const std::array<T, Z>& z)
408 std::array<T, X + Y + Z> result = {};
409 for (
size_t i = 0; i < X; ++i) result[ i] = x[i];
410 for (
size_t i = 0; i < Y; ++i) result[X + i] = y[i];
411 for (
size_t i = 0; i < Z; ++i) result[X + Y + i] = z[i];
417template<
typename Key,
typename Value,
typename Key2>
418[[nodiscard]]
const Value*
lookup(
const std::map<Key, Value>& m,
const Key2& k)
421 return (it != m.end()) ? &it->second :
nullptr;
424template<
typename Key,
typename Value,
typename Key2>
425[[nodiscard]] Value*
lookup(std::map<Key, Value>& m,
const Key2& k)
428 return (it != m.end()) ? &it->second :
nullptr;
432template<
class... Ts>
struct overloaded : Ts... {
using Ts::operator()...; };
443template<
typename T,
typename... Ts>
445 : std::integral_constant<size_t, std::variant<get_index_tag<Ts>...>(get_index_tag<T>()).index()> {};
451template<
typename T,
typename F,
size_t... Is>
452[[nodiscard]]
static constexpr auto generate_array(
F f, std::index_sequence<Is...>)
453 -> std::array<T,
sizeof...(Is)>
458template<
size_t N,
typename F>
459[[nodiscard]]
static constexpr auto generate_array(
F f)
461 using T =
decltype(f(0));
462 return generate_array<T>(f, std::make_index_sequence<N>{});
469 return static_cast<std::underlying_type_t<E>
>(e);
473template<
typename Enum,
typename T,
size_t S = size_t(-1)>
476 [[nodiscard]]
static constexpr size_t get_size_helper() {
477 if constexpr (
requires { Enum::NUM; }) {
478 return (
S ==
size_t(-1)) ?
static_cast<size_t>(Enum::NUM) :
S;
496 [[nodiscard]]
constexpr auto end()
const {
return storage.end(); }
500 [[nodiscard]]
constexpr auto size()
const {
return storage.size(); }
502 [[nodiscard]]
constexpr const auto*
data()
const {
return storage.data(); }
508template<
typename Iterator,
typename Sentinel>
513 : first(first_), last(last_) {}
515 Iterator
begin()
const {
return first; }
516 Sentinel
end()
const {
return last; }
iterator_range(Iterator first_, Sentinel last_)
std::conditional_t< std::is_same_v< T, void >, typename std::iterator_traits< Iterator >::value_type, T > ToVectorType
constexpr size_t sum_of_sizes(const Ranges &... ranges)
constexpr auto sum(InputRange &&range, Proj proj={})
ITER find_unguarded(ITER first, ITER last, const VAL &val, Proj proj={})
Faster alternative to 'find' when it's guaranteed that the value will be found (if not the behavior i...
const Value * lookup(const std::map< Key, Value > &m, const Key2 &k)
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))> >
std::pair< OutputIt, ForwardIt > partition_copy_remove(ForwardIt first, ForwardIt last, OutputIt out_true, UnaryPredicate p)
This is like a combination of partition_copy() and remove().
constexpr ITER find_if_unguarded(ITER first, ITER last, PRED pred)
Faster alternative to 'find_if' when it's guaranteed that the predicate will be true for at least one...
constexpr auto to_underlying(E e) noexcept
auto min_value(InputIterator first, InputIterator last, Proj proj={})
void append(std::vector< T > &v, Tail &&... tail)
auto max_value(InputIterator first, InputIterator last, Proj proj={})
constexpr auto concatArray(const std::array< T, X > &x, const std::array< T, Y > &y)
auto transform_in_place(ForwardRange &&range, UnaryOperation op)
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
auto concat(const Range &range, Tail &&... tail)
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
constexpr auto rfind_if_unguarded(RANGE &range, PRED pred)
bool operator()(Args &&...) const
constexpr auto size() const
constexpr auto empty() const
friend constexpr auto operator<=>(const array_with_enum_index &x, const array_with_enum_index &y)=default
constexpr const auto & operator[](Enum e) const
constexpr const auto * data() const
constexpr auto begin() const
constexpr auto end() const
constexpr auto & operator[](Enum e)
std::array< T, get_size_helper()> storage