7#include "min-cpp-version/cpp20.h"
19 template<
size_t I,
typename... Ts>
20 using nth_type_of = std::tuple_element_t<I, std::tuple<Ts...>>;
21 template<
typename... Ts>
22 using first_type_of = std::tuple_element_t<0, std::tuple<Ts...>>;
23 template<
typename... Ts>
24 using last_type_of = std::tuple_element_t<(
sizeof...(Ts) - 1), std::tuple<Ts...>>;
26 template <
size_t I,
typename T,
typename... Ts>
27 [[nodiscard]]
auto nth_value_of(T&& t, Ts&&... args)
30 return std::forward<T>(t);
33 using return_type =
typename nth_type_of<I, T, Ts...>::type;
34 return std::forward<return_type>(nth_value_of<I - 1>((std::forward<Ts>(args))...));
38 template <
typename... Ts>
39 [[nodiscard]]
auto first_value_of(Ts&&... args)
41 using return_type =
typename first_type_of<Ts...>::type;
42 return std::forward<return_type>(nth_value_of<0>((std::forward<Ts>(args))...));
45 template <
typename... Ts>
46 [[nodiscard]]
auto last_value_of(Ts&&... args)
48 using return_type =
typename last_type_of<Ts...>::type;
49 return std::forward<return_type>(nth_value_of<
sizeof...(Ts) - 1>((std::forward<Ts>(args))...));
56 template <
typename... ARGS,
typename FUNC>
61 template <
typename FUNC,
typename... ARGS>
62 requires ((
sizeof...(ARGS) % 2) == 0)
66 template<
typename... ARGS,
typename FUNC>
70 template<
typename... ARGS,
typename FUNC>
76 template <
typename FUNC,
typename... ARGS>
81 template <
size_t N,
typename FUNC,
typename... ARGS>
82 requires (N <
sizeof...(ARGS))
87 template <
size_t Begin,
size_t End,
size_t Stride,
double&...,
typename FUNC,
typename... ARGS>
92 template <
size_t Begin,
size_t End,
double&...,
typename FUNC,
typename... ARGS>
97 template <
size_t Begin,
double&...,
typename FUNC,
typename... ARGS>
102 template<
typename C,
typename X >
103 [[nodiscard]]
auto is(X
const&) ->
bool {
107 template<
typename C,
typename X >
108 requires std::is_same_v<C, X>
109 [[nodiscard]]
auto is(X
const&) ->
bool {
113 template<
typename C,
typename X >
114 requires (std::is_base_of_v<C, X> && !std::is_same_v<C, X>)
115 [[nodiscard]]
auto is(X
const&) ->
bool {
119 template<
typename C,
typename X >
120 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
121 [[nodiscard]]
auto is(X
const& x) ->
bool {
122 return dynamic_cast<C const*
>(&x) !=
nullptr;
125 template<
typename C,
typename X >
126 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
127 [[nodiscard]]
auto is(X
const* x) ->
bool {
128 return dynamic_cast<C const*
>(x) !=
nullptr;
131 template<
typename C,
typename X >
132 requires dereferenceable<X> && std::is_default_constructible_v<X> && std::is_same_v<C, void>
133 [[nodiscard]]
auto is(X
const& x) ->
bool
138 template<
typename C >
139 [[nodiscard]]
auto as(...) ->
auto {
143 template<
typename C,
typename X >
144 requires std::is_same_v<C, X>
145 [[nodiscard]]
auto as(X
const& x) ->
auto&& {
149 template<
typename C,
typename X >
150 [[nodiscard]]
auto as(X
const& x) ->
auto
151 requires (!std::is_same_v<C, X> && std::constructible_from<C, X const&>)
156 template<
typename C,
typename X >
157 requires std::is_base_of_v<C, X>
158 [[nodiscard]]
auto as(X&& x) -> C&& {
159 return std::forward<X>(x);
162 template<
typename C,
typename X >
163 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
164 [[nodiscard]]
auto as(X& x) -> C& {
165 return dynamic_cast<C&
>(x);
168 template<
typename C,
typename X >
169 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
170 [[nodiscard]]
auto as(X
const& x) -> C
const& {
171 return dynamic_cast<C const&
>(x);
174 template<
typename C,
typename X >
175 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
176 [[nodiscard]]
auto as(X* x) -> C* {
177 return dynamic_cast<C*
>(x);
180 template<
typename C,
typename X >
181 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
182 [[nodiscard]]
auto as(X
const* x) -> C
const* {
183 return dynamic_cast<C const*
>(x);
189 template <
typename T,
typename>
192 template <
size_t I,
typename... Ts>
193 struct get_index_impl : std::integral_constant<size_t, (size_t)-1>
198 template <
size_t I,
typename T,
typename... Ts>
199 struct get_index_impl<I, T, T, Ts...>
200 : std::integral_constant<size_t, I>
203 template <
size_t I,
typename T,
typename U,
typename... Ts>
204 struct get_index_impl<I, T, U, Ts...>
205 : get_index_impl<I + 1, T, Ts...>
208 template <
typename T,
typename... Ts>
210 : get_index_impl<0, T, Ts...>
213 template <
typename T,
typename... Ts>
215 : get_index_impl<0, T, Ts...>
219 template <
typename TYPE,
typename TYPE_CONTAINER>
222 template <
typename TYPE,
typename TYPE_CONTAINER>
230 template<
typename T,
typename... Ts>
231 [[nodiscard]]
auto is(std::variant<Ts...>
const& x)
233 if constexpr (std::is_same_v<T, void>)
235 if (x.valueless_by_exception())
return true;
236 if constexpr (is_any_of_v<std::monostate, Ts...>)
237 return std::get_if<std::monostate>(&x) !=
nullptr;
239 return get_index_v<T, std::variant<Ts...>> == x.index();
242 template<
typename T,
typename... Ts>
243 [[nodiscard]]
auto as(std::variant<Ts...>
const& x)
245 return std::get<T>(x);
251 template<
typename T,
typename X>
252 requires (std::is_same_v<X, std::any> && !std::is_same_v<T, std::any> && !std::is_same_v<T, void>)
253 [[nodiscard]]
constexpr auto is(X
const& x) ->
bool
255 return x.type() ==
typeid(T);
258 template<
typename T,
typename X>
259 requires (std::is_same_v<X, std::any> && std::is_same_v<T, void>)
260 [[nodiscard]]
constexpr auto is(X
const& x) ->
bool
262 return !x.has_value();
265 template<
typename T,
typename X>
266 requires (!std::is_reference_v<T> && std::is_same_v<X, std::any> && !std::is_same_v<T, std::any>)
267 [[nodiscard]]
constexpr auto as(X
const& x) -> T
269 return std::any_cast<T>(x);
276 template<
typename T,
typename X>
277 requires std::is_same_v<X, std::optional<T>>
278 [[nodiscard]]
constexpr auto is(X
const& x) ->
bool
280 return x.has_value();
283 template<
typename T,
typename U>
284 requires std::is_same_v<T, void>
285 [[nodiscard]]
constexpr auto is(std::optional<U>
const& x) ->
bool
287 return !x.has_value();
290 template<
typename T,
typename X>
291 requires std::is_same_v<X, std::optional<T>>
292 [[nodiscard]]
constexpr auto as(X
const& x) ->
auto&&
304 template <
auto = [] {}>
305 struct unique_type {};
315 template <
typename T>
316 requires (!std::is_same_v<T, pass_identity>)
317 T
operator* (T&& obj)
const {
return std::forward<T>(obj); }
319 pass_identity operator* (pass_identity&&)
const {
return {}; }
322 template <
typename T>
323 requires (!std::is_same_v<T, pass_identity>)
324 T
operator* (T&& obj, pass_identity&& p) {
return std::forward<T>(obj); }
326 constexpr size_t not_given = std::numeric_limits<size_t>::max();
329 template <
typename FUNC,
typename... ARGS>
330 requires ((
sizeof...(ARGS) % 2) == 0)
333 if constexpr (
sizeof...(args) > 1)
335 [&]<
typename T1,
typename T2,
typename... NEW_ARGS>(T1 && t1, T2 && t2, NEW_ARGS&&... new_args) {
336 f(std::forward<T1>(t1), std::forward<T2>(t2));
337 if constexpr (
sizeof...(args) > 1)
339 }(std::forward<ARGS>(args)...);
397 template <
size_t INDEX,
typename VALUE,
typename FUNC>
398 constexpr void call(VALUE&& value, FUNC&& func)
400 if constexpr (std::is_invocable_v<FUNC, std::integral_constant<size_t, INDEX>, VALUE>)
401 func(std::integral_constant<size_t, INDEX>{}, std::forward<VALUE>(value));
402 else if constexpr (std::is_invocable_v<FUNC, VALUE, std::integral_constant<size_t, INDEX>>)
403 func(std::forward<VALUE>(value), std::integral_constant<size_t, INDEX>{});
404 else if constexpr (std::is_invocable_v<FUNC, VALUE, size_t>)
405 func(std::forward<VALUE>(value), INDEX);
406 else if constexpr (std::is_invocable_v<FUNC, size_t, VALUE>)
407 func(INDEX, std::forward<VALUE>(value));
408 else if constexpr (std::is_invocable_v<FUNC, VALUE>)
409 func(std::forward<VALUE>(value));
410 else if constexpr (std::is_invocable_v<FUNC, size_t, std::type_identity<VALUE>>)
411 func(std::forward<VALUE>(value));
416 template <
size_t INDEX,
typename VALUE,
typename FUNC>
417 constexpr auto call_r(VALUE&& value, FUNC&& func)
419 if constexpr (std::is_invocable_v<FUNC, std::integral_constant<size_t, INDEX>, VALUE>)
420 return func(std::integral_constant<size_t, INDEX>{}, std::forward<VALUE>(value));
421 else if constexpr (std::is_invocable_v<FUNC, VALUE, std::integral_constant<size_t, INDEX>>)
422 return func(std::forward<VALUE>(value), std::integral_constant<size_t, INDEX>{});
423 else if constexpr (std::is_invocable_v<FUNC, VALUE, size_t>)
424 return func(std::forward<VALUE>(value), INDEX);
425 else if constexpr (std::is_invocable_v<FUNC, size_t, VALUE>)
426 return func(INDEX, std::forward<VALUE>(value));
427 else if constexpr (std::is_invocable_v<FUNC, VALUE>)
428 return func(std::forward<VALUE>(value));
433 template<
typename T,
typename FUNC,
size_t... Is>
434 constexpr void do_for_each_in_tuple(T&& t, FUNC
const& f, std::index_sequence<Is...>)
441 template<
typename T,
typename FUNC,
size_t... Is>
442 constexpr bool do_for_each_in_tuple_cond(T&& t, FUNC
const& f, std::index_sequence<Is...>)
444 return (call_r<Is>(std::get<Is>(t), f) && ...);
447 template<
typename T,
typename FUNC,
size_t... Is>
448 constexpr auto do_transform_tuple(T&& t, FUNC
const& f, std::index_sequence<Is...>)
450 return std::make_tuple(call_r<Is>(
455 template<
typename... ARGS,
typename FUNC,
size_t... Is>
456 constexpr void do_for_each(FUNC
const& f, std::index_sequence<Is...>)
458 (call<Is>(std::type_identity<ARGS>{}, f), ...);
462 template <
typename... ARGS,
typename FUNC>
465 detail::do_for_each<ARGS...>(std::forward<FUNC>(f), std::make_index_sequence<
sizeof...(ARGS)>());
468 template<
typename... ARGS,
typename FUNC>
471 if constexpr (std::same_as<bool, decltype(detail::call_r<0>(std::get<0>(t), f))>)
472 return detail::do_for_each_in_tuple_cond(t, std::forward<FUNC>(f), std::make_index_sequence<
sizeof...(ARGS)>());
474 detail::do_for_each_in_tuple(t, std::forward<FUNC>(f), std::make_index_sequence<
sizeof...(ARGS)>());
477 template<
typename... ARGS,
typename FUNC>
480 if constexpr (std::same_as<bool, decltype(detail::call_r<0>(std::get<0>(t), f))>)
481 return detail::do_for_each_in_tuple_cond(std::move(t), std::forward<FUNC>(f), std::make_index_sequence<
sizeof...(ARGS)>());
483 detail::do_for_each_in_tuple(std::move(t), std::forward<FUNC>(f), std::make_index_sequence<
sizeof...(ARGS)>());
486 template<
typename... ARGS,
typename FUNC>
489 return detail::do_transform_tuple(t, std::forward<FUNC>(f), std::make_index_sequence<
sizeof...(ARGS)>());
492 template <
typename FUNC,
typename... ARGS>
508 []<
size_t... INDICES,
typename FUNC2,
typename TUPLE>(FUNC2
const& func, std::index_sequence<INDICES...>, TUPLE&& tuple) {
509 (detail::call<INDICES>(
510 std::get<INDICES>(tuple)
512 }(std::forward<FUNC>(f), std::make_index_sequence<
sizeof...(ARGS)>{}, std::forward_as_tuple(std::forward<ARGS>(args)...));
518 template <
size_t I,
typename FUNC,
typename... ARGS>
519 requires (I <
sizeof...(ARGS))
522 return [&] <
size_t... Idxs>(std::index_sequence<Idxs...>) {
524 static_assert(std::is_invocable_v<FUNC, ARGS>,
"Cannot invoke callback with this type");
525 if constexpr (Idxs == I)
526 return f(std::forward<ARGS>(args));
528 return detail::pass_identity{};
530 }(std::make_index_sequence<
sizeof...(args)>{});
535 template <
size_t,
size_t = detail::not_given,
size_t = 1,
class = std::
integral_constant<
size_t, 0>>
538 template <
size_t Begin,
size_t End,
size_t Str
ide,
size_t I>
539 struct pack_slicer<Begin, End, Stride, std::integral_constant<size_t, I>>
541 static constexpr bool include = I >= Begin && I < End && ((I - Begin) % Stride == 0);
543 using next = pack_slicer<Begin, End, Stride, std::integral_constant<size_t, I + 1>>;
545 template <
typename T,
typename... ARGS>
546 static constexpr auto make_slice_function(T&& t, ARGS&&... ts)
548 return [slicer = next::make_slice_function(std::forward<ARGS>(ts)...), nt = std::forward<T>(t)]<
typename CALLBACK_TYPE>(CALLBACK_TYPE && cb)
mutable {
549 if constexpr (include)
551 return slicer([t = std::forward<T>(nt), &cb]<
typename... NEW_ARGS>(NEW_ARGS&&... sl)
mutable {
return cb(std::forward<T>(t), std::forward<NEW_ARGS>(sl)...); });
553 return slicer([&cb]<
typename... NEW_ARGS>(NEW_ARGS&&... sl)
mutable {
return cb(std::forward<NEW_ARGS>(sl)...); });
557 static constexpr auto make_slice_function() {
return [](
auto&& cb)
mutable {
return cb(); }; }
561 template <
size_t Begin,
size_t End,
size_t Stride,
double&...,
typename FUNC,
typename... ARGS>
564 return ::ghassanpl::detail::pack_slicer<Begin, End, Stride>::make_slice_function(std::forward<ARGS>(args)...)(std::forward<FUNC>(callback));
567 template <
size_t Begin,
size_t End,
double&...,
typename FUNC,
typename... ARGS>
570 return ::ghassanpl::detail::pack_slicer<Begin, End>::make_slice_function(std::forward<ARGS>(args)...)(std::forward<FUNC>(callback));
573 template <
size_t Begin,
double&...,
typename FUNC,
typename... ARGS>
576 return ::ghassanpl::detail::pack_slicer<Begin>::make_slice_function(std::forward<ARGS>(args)...)(std::forward<FUNC>(callback));
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.
constexpr void for_each_pair(FUNC &&f, ARGS &&... args)
Function: for_each_pair TODO: Description.
constexpr auto transform_tuple(std::tuple< ARGS... > const &t, FUNC &&f)
Function: transform_tuple.
constexpr void for_each(FUNC &&f)
Function: for_each TODO: Description.
constexpr auto for_each_in_tuple(std::tuple< ARGS... > const &t, FUNC &&f)
Function: for_each_in_tuple.
constexpr auto apply_to_slice(FUNC &&f, ARGS &&... args)
Function: apply_to_slice Calls f with a slice of the args pack.
constexpr void enumerate_pack(FUNC &&f, ARGS &&... args)
Function: enumerate_pack Calls f on every argument args....
auto is(X const &) -> bool
Shamelessly stolen from hsutter's cppfront.
constexpr auto apply_to_nth(FUNC &&f, ARGS &&... args)
Function: apply_to_nth Calls f on the Nth argument in the args pack.
std::variant get index of type