19 using std::ranges::random_access_range;
20 using std::ranges::contiguous_range;
21 using std::random_access_iterator;
25 template <
typename RANGE>
26 using range_value = std::ranges::range_value_t<std::decay_t<RANGE>>;
29 template <
typename RANGE>
33 template <
typename RANGE,
typename FUNC>
39 return index >= 0 && index < std::ranges::size(
range);
59 constexpr decltype(
auto)
at(random_access_range
auto&
range, std::integral
auto index)
62 throw std::invalid_argument(
"index");
63 return *(std::ranges::begin(
range) + index);
67 constexpr auto at_ptr(random_access_range
auto&
range, std::integral
auto index)
68 ->
decltype(std::to_address(std::ranges::begin(
range) + index))
72 return std::to_address(std::ranges::begin(
range) + index);
77 constexpr decltype(
auto)
modulo_at(random_access_range
auto&
range, std::integral
auto index)
83 template <random_access_range RANGE,
typename T>
84 constexpr auto index_of(
RANGE const&
range, T&& value) -> std::iter_difference_t<range_iterator<RANGE>>
85 requires requires (T value,
RANGE range) { { *std::ranges::begin(
range) == value } -> std::convertible_to<bool>; }
87 const auto it = std::ranges::find(
range, std::forward<T>(value));
88 if (
it == std::ranges::end(
range))
90 return std::ranges::distance(std::ranges::begin(
range),
it);
94 template <random_access_range RANGE,
typename T = range_value<RANGE>>
102 template <random_access_range RANGE,
typename FUNC>
106 const auto it = std::ranges::find_if(
range, std::forward<FUNC>(
func));
107 if (
it == std::ranges::end(
range))
109 return std::ranges::distance(std::ranges::begin(
range),
it);
113 template <std::ranges::range RANGE,
typename FUNC>
117 const auto it = std::ranges::find_if(
range, std::forward<FUNC>(
func));
121 template <random_access_range RANGE,
typename FUNC,
typename DEF_TYPE = range_value<RANGE>>
125 auto it = std::ranges::find_if(
range, std::forward<FUNC>(
func));
126 if (
it == std::ranges::end(
range))
132 constexpr auto to_index(random_access_iterator
auto iterator, random_access_range
auto const&
range)
134 return std::ranges::distance(std::ranges::begin(
range), iterator);
138 template <contiguous_range RANGE>
141 if (std::ranges::empty(
range))
return false;
142 return pointer >= std::to_address(std::ranges::begin(
range)) && pointer < std::to_address(std::ranges::end(
range));
147 template <
typename T,
size_t N = std::dynamic_extent>
148 constexpr std::pair<std::span<T>, std::span<T>>
split_at(std::span<T, N>
span,
size_t index)
150 if (index >=
span.size())
151 return {
span, std::span<T>{} };
152 return {
span.subspan(0, index),
span.subspan(index) };
155 template <
typename T,
size_t N = std::dynamic_extent>
156 constexpr std::array<std::span<T>, 3>
split_at(std::span<T, N>
span,
size_t index,
size_t size)
158 if (index >=
span.size() || index + size >=
span.size())
159 return {
span, std::span<T>{}, std::span<T>{} };
160 return {
span.subspan(0, index),
span.subspan(index, size),
span.subspan(index + size) };
163 template <
typename T,
size_t N = std::dynamic_extent>
164 constexpr std::pair<T*, T*> as_range(std::span<T, N>
span)
171 template <
typename TO,
typename FROM,
size_t N = std::dynamic_extent>
174 return std::span<TO>{
reinterpret_cast<TO*
>(
bytes.data()), (
bytes.size() *
sizeof(
FROM)) /
sizeof(
TO) };
177 template <
typename T1,
size_t N1,
typename T2,
size_t N2>
178 constexpr bool are_adjacent(std::span<T1, N1>
s1, std::span<T2, N2>
s2)
180 return reinterpret_cast<char const*
>(
s1.data() +
s1.size()) ==
reinterpret_cast<char const*
>(
s2.data())
181 ||
reinterpret_cast<char const*
>(
s2.data() +
s2.size()) ==
reinterpret_cast<char const*
>(
s1.data());
184 template <
typename T1,
size_t N1,
typename T2,
size_t N2>
185 constexpr bool are_overlapping(std::span<T1, N1>
s1, std::span<T2, N2>
s2)
190 template <
typename T,
size_t N1,
typename U,
size_t N2>
191 requires std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
192 constexpr bool ends_with(std::span<T, N1>
s1, std::span<U, N2>
s2)
194 if (
s1.size() <
s2.size())
return false;
195 return std::ranges::equal(
s1.subspan(
s1.size() -
s2.size()),
s2);
198 template <
typename T,
size_t N1,
typename U,
size_t N2>
199 requires std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
200 constexpr bool starts_with(std::span<T, N1>
s1, std::span<U, N2>
s2)
202 if (
s1.size() <
s2.size())
return false;
203 return std::ranges::equal(
s1.subspan(0,
s2.size()),
s2);
208 template <
typename T, std::size_t...
Ns>
211 std::array<T, (
Ns + ...)> result;
212 std::size_t index = 0;
213 ((std::copy_n(std::make_move_iterator(
arrays.begin()),
Ns, result.begin() + index), index +=
Ns), ...);
217 template<
typename T,
size_t LL,
typename...
ARGS>
218 requires (std::same_as<std::remove_cvref_t<ARGS>, T> && ...)
221 std::array<T,
LL +
sizeof...(ARGS)>
ar;
222 auto current = std::move(
rhs.begin(),
rhs.end(),
ar.begin());
223 ((*current++ =
args), ...);
227#ifndef __cpp_lib_ranges_contains
231 template <std::input_iterator I, std::sentinel_for<I> S,
class T,
class Proj = std::
identity>
232 requires std::indirect_binary_predicate<std::ranges::equal_to, std::projected<I, Proj>,
const T*>
238 template <std::ranges::input_range R,
class T,
class Proj = std::
identity>
239 requires std::indirect_binary_predicate<std::ranges::equal_to, std::projected<std::ranges::iterator_t<R>,
Proj>,
const T*>
240 constexpr bool operator()(R&&
r,
const T& value,
Proj proj = {})
const
242 return (*
this)(std::ranges::begin(
r), std::ranges::end(
r), std::move(value),
proj);
250 struct __contains_subrange_fn
252 template <std::forward_iterator I1, std::sentinel_for<I1> S1, std::forward_iterator I2, std::sentinel_for<I2> S2,
class Pred = std::ranges::equal_to,
class Proj1 = std::
identity,
class Proj2 = std::
identity>
253 requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
259 template <std::ranges::forward_range R1, std::ranges::forward_range R2,
class Pred = std::ranges::equal_to,
class Proj1 = std::
identity,
class Proj2 = std::
identity>
260 requires std::indirectly_comparable<std::ranges::iterator_t<R1>, std::ranges::iterator_t<R2>,
Pred,
Proj1,
Proj2>
263 return (*
this)(std::ranges::begin(
r1), std::ranges::end(
r1), std::ranges::begin(
r2), std::ranges::end(
r2), std::move(
pred), std::move(
proj1), std::move(
proj2));
273#ifndef __cpp_lib_ranges_to_container
277 struct from_range_t {
explicit from_range_t() =
default; };
278 constexpr inline from_range_t from_range;
280 template <
class RANGE,
class CONTAINER>
281 concept _Ref_converts = std::convertible_to<std::ranges::range_reference_t<RANGE>, std::ranges::range_value_t<CONTAINER>>;
293 && std::input_iterator<std::ranges::iterator_t<RANGE>>
294 && std::constructible_from<CONTAINER, std::ranges::iterator_t<RANGE>, std::ranges::iterator_t<RANGE>,
TYPES...>;
296 template <
class CONTAINER,
class REFERENCE>
301 template <
class CONTAINER,
class REFERENCE>
314 template <
class REFERENCE,
class CONTAINER>
318 return std::back_insert_iterator{
_Cont };
321 return std::insert_iterator{
_Cont,
_Cont.end() };
325 template <
class RANGE,
class CONTAINER>
326 concept sized_and_reservable =
327 std::ranges::sized_range<RANGE> &&
328 std::ranges::sized_range<CONTAINER> &&
331 {
container.capacity() } -> std::same_as<std::ranges::range_size_t<CONTAINER>>;
332 {
container.max_size() } -> std::same_as<std::ranges::range_size_t<CONTAINER>>;
335 template <std::ranges::input_range RANGE>
336 struct phony_input_iterator
338 using iterator_category = std::input_iterator_tag;
339 using value_type = std::ranges::range_value_t<RANGE>;
341 using pointer = std::add_pointer_t<std::ranges::range_reference_t<RANGE>>;
342 using reference = std::ranges::range_reference_t<RANGE>;
344 reference operator*()
const;
345 pointer operator->()
const;
347 phony_input_iterator& operator++();
348 phony_input_iterator operator++(
int);
350 bool operator==(
const phony_input_iterator&)
const;
357 return static_cast<decltype(
CONTAINER(std::declval<RANGE>(), std::declval<ARGS>()...))*
>(
nullptr);
359 return static_cast<decltype(
CONTAINER(from_range, std::declval<RANGE>(), std::declval<ARGS>()...))*
>(
nullptr);
361 return static_cast<decltype(
CONTAINER(std::declval<phony_input_iterator<RANGE>
>(), std::declval<phony_input_iterator<RANGE>>(), std::declval<ARGS>()...))*>(
nullptr);
368 requires (!std::ranges::view<CONTAINER>)
375 return CONTAINER(from_range, std::forward<RANGE>(
range), std::forward<TYPES>(
args)...);
384 std::ranges::copy(
range, detail::container_inserter<std::ranges::range_reference_t<RANGE>>(
container));
387 else if constexpr (std::ranges::input_range<std::ranges::range_reference_t<RANGE>>)
389 const auto transform = [](
auto&&
_Elem) {
Concept to check if a function is a predicate on the range elements (i.e. returns boolable)
constexpr auto bit_count
Equal to the number of bits in the type.
auto at_ptr(std::map< K, V, C > const &map, VAL &&value)
Same as map_find()
constexpr auto join(std::array< T, Ns >... arrays)
Arrays.
constexpr auto index_of(RANGE const &range, T &&value) -> std::iter_difference_t< range_iterator< RANGE > >
Find a value in range and returns an index to it.
std::ranges::range_value_t< std::decay_t< RANGE > > range_value
Helper template to get the value type of a type that decays to a range
constexpr decltype(auto) at(random_access_range auto &range, std::integral auto index)
Returns a reference to the value at index of range
constexpr std::pair< std::span< T >, std::span< T > > split_at(std::span< T, N > span, size_t index)
Span stuff.
constexpr bool valid_address(RANGE &&range, range_value< RANGE > *pointer)
Returns whether or not pointer is a valid pointer to an element in the contiguous range
constexpr __contains_subrange_fn contains_subrange
contains_subrange(range, subrange)
constexpr auto to_index(random_access_iterator auto iterator, random_access_range auto const &range)
Turns an iterator to range to an index.
auto span_cast(std::span< FROM, N > bytes) noexcept
Casts a span of objects of type FROM to a span of objects of type TO Does not perform any checks,...
constexpr bool valid_index(random_access_range auto &range, std::integral auto index)
Returns whether or not a given integer is a valid index to a random access range
constexpr auto at_or_default(RANGE &&range, std::integral auto index, T &&default_value)
Return the element at index or default_value if not a valid index.
constexpr auto modulo_index(size_t range_size, std::integral auto index)
Returns index converted to a valid index into a range of range_size as if using modulo arithmetic.
constexpr auto find_index(RANGE const &range, FUNC &&func) -> std::iter_difference_t< range_iterator< RANGE > >
Find a value in range and returns an index to it.
constexpr CONTAINER to(RANGE &&range, TYPES &&... args)
to<container>();
std::ranges::iterator_t< std::decay_t< RANGE > > range_iterator
Helper template to get the iterator type of a type that decays to a range
constexpr auto find_ptr(RANGE &range, FUNC &&func)
Find a value in range and returns a pointer to it, or null if none found.
constexpr __contains_fn contains
contains(range, el)
constexpr decltype(auto) modulo_at(random_access_range auto &range, std::integral auto index)
Returns a reference to the value at modulo_index of range
The below code is based on Sun's libm library code, which is licensed under the following license:
Primary namespace for everything in this library.