8#include <initializer_list>
19 template<
typename ...Args>
31template<
typename ITER,
typename VAL>
32[[nodiscard]]
constexpr bool contains(ITER first, ITER last,
const VAL& val)
35 while (first != last) {
36 if (*first == val)
return true;
41template<
typename RANGE,
typename VAL>
42[[nodiscard]]
constexpr bool contains(
const RANGE& range,
const VAL& val)
44 return contains(std::begin(range), std::end(range), val);
47template<
typename ITER,
typename VAL,
typename Proj>
48[[nodiscard]]
bool contains(ITER first, ITER last,
const VAL& val, Proj proj)
51 while (first != last) {
52 if (std::invoke(proj, *first) == val)
return true;
57template<
typename RANGE,
typename VAL,
typename Proj>
58[[nodiscard]]
bool contains(
const RANGE& range,
const VAL& val, Proj proj)
60 return contains(std::begin(range), std::end(range), val, proj);
71template<
typename ITER,
typename VAL,
typename Proj = std::
identity>
72[[nodiscard]] ITER
find_unguarded(ITER first, ITER last,
const VAL& val, Proj proj = {})
75 [&](
const auto& e) {
return std::invoke(proj, e) == val; });
77template<
typename RANGE,
typename VAL,
typename Proj = std::
identity>
78[[nodiscard]]
auto find_unguarded(RANGE& range,
const VAL& val, Proj proj = {})
80 return find_unguarded(std::begin(range), std::end(range), val, proj);
87template<
typename ITER,
typename PRED>
92 assert(first != last);
93 if (pred(*first))
return first;
97template<
typename RANGE,
typename PRED>
108template<
typename RANGE,
typename VAL,
typename Proj = std::
identity>
111 auto it =
find_unguarded(std::rbegin(range), std::rend(range), val, proj);
116template<
typename RANGE,
typename PRED>
133template<
typename VECTOR>
146 if (&*it != &v.back()) {
147 *it = std::move(v.back());
168template<
typename ForwardIt,
typename OutputIt,
typename UnaryPredicate>
170 ForwardIt first, ForwardIt last, OutputIt out_true, UnaryPredicate p)
172 first = std::find_if(first, last, p);
173 auto out_false = first;
176 while (first != last) {
178l_true: *out_true++ = std::move(*first++);
180 *out_false++ = std::move(*first++);
184 return std::pair(out_true, out_false);
187template<
typename ForwardRange,
typename OutputIt,
typename UnaryPredicate>
195template<
typename ForwardRange,
typename UnaryOperation>
198 return std::transform(std::begin(range), std::end(range), std::begin(range), op);
204template<
typename InputIterator,
typename Proj = std::
identity>
205[[nodiscard]]
auto min_value(InputIterator first, InputIterator last, Proj proj = {})
207 assert(first != last);
208 auto result = std::invoke(proj, *first++);
209 while (first != last) {
210 result = std::min(result, std::invoke(proj, *first++));
215template<
typename InputRange,
typename Proj = std::
identity>
216[[nodiscard]]
auto min_value(InputRange&& range, Proj proj = {})
218 return min_value(std::begin(range), std::end(range), proj);
223template<
typename InputIterator,
typename Proj = std::
identity>
224[[nodiscard]]
auto max_value(InputIterator first, InputIterator last, Proj proj = {})
226 assert(first != last);
227 auto result = std::invoke(proj, *first++);
228 while (first != last) {
229 result = std::max(result, std::invoke(proj, *first++));
234template<
typename InputRange,
typename Proj = std::
identity>
235[[nodiscard]]
auto max_value(InputRange&& range, Proj proj = {})
237 return max_value(std::begin(range), std::end(range), proj);
244template<
typename InputRange,
typename Proj = std::
identity>
245[[nodiscard]]
constexpr auto sum(InputRange&& range, Proj proj = {})
247 using Iter =
decltype(std::begin(range));
248 using VT =
typename std::iterator_traits<Iter>::value_type;
249 using RT =
decltype(std::invoke(proj, std::declval<VT>()));
251 auto first = std::begin(range);
252 auto last = std::end(range);
254 while (first != last) {
255 init = std::move(init) + std::invoke(proj, *first++);
262 template<
typename T,
typename Iterator>
264 std::is_same_v<T, void>,
265 typename std::iterator_traits<Iterator>::value_type,
274template<
typename T =
void,
typename Range>
278 return {std::begin(range), std::end(range)};
292template<
typename... Ranges>
295 return (0 + ... + std::distance(std::begin(
ranges), std::end(
ranges)));
298template<
typename Result>
304template<
typename Result,
typename Range,
typename... Tail>
305void append(Result& x, Range&& y, Tail&&... tail)
314 x.emplace_back(std::forward<
decltype(e)>(e));
317 x.insert(std::end(x), std::begin(y), std::end(y));
325template<
typename Result,
typename T2,
typename... Tail>
326void append(Result& x, std::vector<T2>&& y, Tail&&... tail)
328 x.insert(std::end(x),
329 std::move_iterator(std::begin(y)),
330 std::move_iterator(std::end(y)));
337template<
typename T,
typename... Tail>
338void append(std::vector<T>& v, Tail&&... tail)
341 auto current = v.size();
342 if (
auto required = current + extra;
343 v.capacity() < required) {
344 v.reserve(current + std::max(current, extra));
353void append(std::vector<T>& v, std::vector<T>&& range)
356 v = std::move(range);
358 v.insert(std::end(v),
359 std::move_iterator(std::begin(range)),
360 std::move_iterator(std::end(range)));
365void append(std::vector<T>& x, std::initializer_list<T> list)
367 x.insert(x.end(), list);
371template<
typename T = void,
typename Range,
typename... Tail>
372[[nodiscard]]
auto concat(
const Range& range, Tail&&... tail)
375 std::vector<T2> result;
376 append(result, range, std::forward<Tail>(tail)...);
380template<
typename T,
typename... Tail>
381[[nodiscard]] std::vector<T>
concat(std::vector<T>&& v, Tail&&... tail)
383 append(v, std::forward<Tail>(tail)...);
389template<
typename T,
size_t X,
size_t Y>
390constexpr auto concatArray(
const std::array<T, X>& x,
const std::array<T, Y>& y)
392 std::array<T, X + Y> result = {};
395 for (
size_t i = 0; i < X; ++i) result[0 + i] = x[i];
396 for (
size_t i = 0; i < Y; ++i) result[X + i] = y[i];
400template<
typename T,
size_t X,
size_t Y,
size_t Z>
402 const std::array<T, Y>& y,
403 const std::array<T, Z>& z)
405 std::array<T, X + Y + Z> result = {};
406 for (
size_t i = 0; i < X; ++i) result[ i] = x[i];
407 for (
size_t i = 0; i < Y; ++i) result[X + i] = y[i];
408 for (
size_t i = 0; i < Z; ++i) result[X + Y + i] = z[i];
414template<
typename Key,
typename Value,
typename Key2>
415[[nodiscard]]
const Value*
lookup(
const std::map<Key, Value>& m,
const Key2& k)
418 return (it != m.end()) ? &it->second :
nullptr;
421template<
typename Key,
typename Value,
typename Key2>
422[[nodiscard]] Value*
lookup(std::map<Key, Value>& m,
const Key2& k)
425 return (it != m.end()) ? &it->second :
nullptr;
429template<
class... Ts>
struct overloaded : Ts... {
using Ts::operator()...; };
440template<
typename T,
typename... Ts>
442 : std::integral_constant<size_t, std::variant<get_index_tag<Ts>...>(get_index_tag<T>()).index()> {};
448template<
typename T,
typename F,
size_t... Is>
449[[nodiscard]]
static constexpr auto generate_array(
F f, std::index_sequence<Is...>)
450 -> std::array<T,
sizeof...(Is)>
455template<
size_t N,
typename F>
456[[nodiscard]]
static constexpr auto generate_array(
F f)
458 using T =
decltype(f(0));
459 return generate_array<T>(f, std::make_index_sequence<N>{});
466 return static_cast<std::underlying_type_t<E>
>(e);
470template<
typename Enum,
typename T,
size_t S = size_t(-1)>
473 [[nodiscard]]
static constexpr size_t get_size_helper() {
474 if constexpr (
requires { Enum::NUM; }) {
475 return (
S ==
size_t(-1)) ?
static_cast<size_t>(Enum::NUM) :
S;
493 [[nodiscard]]
constexpr auto end()
const {
return storage.end(); }
497 [[nodiscard]]
constexpr auto size()
const {
return storage.size(); }
499 [[nodiscard]]
constexpr const auto*
data()
const {
return storage.data(); }
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