header_utils
Loading...
Searching...
No Matches
templates.h
1
4
5#pragma once
6
7#include "min-cpp-version/cpp20.h"
8#include <tuple>
9#include <variant>
10#include <optional>
11#include <any>
12
13#include "cpp23.h"
14
17namespace ghassanpl
18{
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...>>;
25
26 template <size_t I, typename T, typename... Ts>
27 [[nodiscard]] auto nth_value_of(T&& t, Ts&&... args)
28 {
29 if constexpr (I == 0)
30 return std::forward<T>(t);
31 else
32 {
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))...));
35 }
36 }
37
38 template <typename... Ts>
39 [[nodiscard]] auto first_value_of(Ts&&... args)
40 {
41 using return_type = typename first_type_of<Ts...>::type;
42 return std::forward<return_type>(nth_value_of<0>((std::forward<Ts>(args))...));
43 }
44
45 template <typename... Ts>
46 [[nodiscard]] auto last_value_of(Ts&&... args)
47 {
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))...));
50 }
51
52
53
56 template <typename... ARGS, typename FUNC>
57 constexpr void for_each(FUNC&& f);
58
61 template <typename FUNC, typename... ARGS>
62 requires ((sizeof...(ARGS) % 2) == 0)
63 constexpr void for_each_pair(FUNC&& f, ARGS&&... args);
64
66 template<typename... ARGS, typename FUNC>
67 constexpr auto for_each_in_tuple(std::tuple<ARGS...> const& t, FUNC&& f);
68
70 template<typename... ARGS, typename FUNC>
71 constexpr auto transform_tuple(std::tuple<ARGS...> const& t, FUNC&& f);
72
76 template <typename FUNC, typename... ARGS>
77 constexpr void enumerate_pack(FUNC&& f, ARGS&&... args);
78
81 template <size_t N, typename FUNC, typename... ARGS>
82 requires (N < sizeof...(ARGS))
83 constexpr auto apply_to_nth(FUNC&& f, ARGS&&... args);
84
87 template <size_t Begin, size_t End, size_t Stride, double&..., typename FUNC, typename... ARGS>
88 constexpr auto apply_to_slice(FUNC&& f, ARGS&&... args);
89
92 template <size_t Begin, size_t End, double&..., typename FUNC, typename... ARGS>
93 constexpr auto apply_to_slice(FUNC&& f, ARGS&&... args);
94
97 template <size_t Begin, double&..., typename FUNC, typename... ARGS>
98 constexpr auto apply_to_slice(FUNC&& f, ARGS&&... args);
99
100
102 template< typename C, typename X >
103 [[nodiscard]] auto is(X const&) -> bool {
104 return false;
105 }
106
107 template< typename C, typename X >
108 requires std::is_same_v<C, X>
109 [[nodiscard]] auto is(X const&) -> bool {
110 return true;
111 }
112
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 {
116 return true;
117 }
118
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;
123 }
124
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;
129 }
130
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
134 {
135 return x == X();
136 }
137
138 template< typename C >
139 [[nodiscard]] auto as(...) -> auto {
140 return nullptr;
141 }
142
143 template< typename C, typename X >
144 requires std::is_same_v<C, X>
145 [[nodiscard]] auto as(X const& x) -> auto&& {
146 return x;
147 }
148
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&>)
152 {
153 return C{ x };
154 }
155
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);
160 }
161
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);
166 }
167
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);
172 }
173
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);
178 }
179
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);
184 }
185
186
188
189 template <typename T, typename>
190 struct get_index;
191
192 template <size_t I, typename... Ts>
193 struct get_index_impl : std::integral_constant<size_t, (size_t)-1>
194 {
195 //static_assert((std::is_same_v<size_t, Ts> && ...), "type not a member");
196 };
197
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>
201 { };
202
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...>
206 { };
207
208 template <typename T, typename... Ts>
209 struct get_index<T, std::variant<Ts...>>
210 : get_index_impl<0, T, Ts...>
211 { };
212
213 template <typename T, typename... Ts>
214 struct get_index<T, std::tuple<Ts...>>
215 : get_index_impl<0, T, Ts...>
216 { };
217
218
219 template <typename TYPE, typename TYPE_CONTAINER>
220 inline constexpr size_t get_index_v = get_index<TYPE, TYPE_CONTAINER>::value;\
221
222 template <typename TYPE, typename TYPE_CONTAINER>
223 inline constexpr bool has_type_v = get_index<TYPE, TYPE_CONTAINER>::value != (size_t)-1;
224
225
226 //-------------------------------------------------------------------------------------------------------------
227 // std::variant is and as
228 //
229
230 template<typename T, typename... Ts>
231 [[nodiscard]] auto is(std::variant<Ts...> const& x)
232 {
233 if constexpr (std::is_same_v<T, void>)
234 {
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;
238 }
239 return get_index_v<T, std::variant<Ts...>> == x.index();
240 }
241
242 template<typename T, typename... Ts>
243 [[nodiscard]] auto as(std::variant<Ts...> const& x)
244 {
245 return std::get<T>(x);
246 }
247
248 //-------------------------------------------------------------------------------------------------------------
249 // std::any is and as
250 //
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
254 {
255 return x.type() == typeid(T);
256 }
257
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
261 {
262 return !x.has_value();
263 }
264
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
268 {
269 return std::any_cast<T>(x);
270 }
271
272
273 //-------------------------------------------------------------------------------------------------------------
274 // std::optional is and as
275 //
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
279 {
280 return x.has_value();
281 }
282
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
286 {
287 return !x.has_value();
288 }
289
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&&
293 {
294 return x.value();
295 }
296
297 //-------------------------------------------------------------------------------------------------------------
298 // unique_type
299 //
300 // usage:
301 // unique_type a;
302 // unique_type b;
303 // static_assert(typeid(a) != typeid(b));
304 template <auto = [] {}>
305 struct unique_type {};
306}
307
308namespace ghassanpl
309{
310
311 namespace detail
312 {
313 struct pass_identity
314 {
315 template <typename T>
316 requires (!std::is_same_v<T, pass_identity>)
317 T operator* (T&& obj) const { return std::forward<T>(obj); }
318
319 pass_identity operator* (pass_identity&&) const { return {}; }
320 };
321
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); }
325
326 constexpr size_t not_given = std::numeric_limits<size_t>::max();
327 }
328
329 template <typename FUNC, typename... ARGS>
330 requires ((sizeof...(ARGS) % 2) == 0)
331 constexpr void for_each_pair(FUNC&& f, ARGS&&... args)
332 {
333 if constexpr (sizeof...(args) > 1)
334 {
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)
338 for_each_pair(f, std::forward<NEW_ARGS>(new_args)...);
339 }(std::forward<ARGS>(args)...);
340 }
341 }
342
343 /*
344 template <typename... ARGS, typename FUNC>
345 constexpr void for_each(FUNC&& f)
346 {
347 [&] <size_t... Idxs>(std::index_sequence<Idxs...>) {
348 ([&] <typename T> (size_t i, std::type_identity<T>) {
349 if constexpr (std::is_invocable_v<FUNC, size_t, std::type_identity<T>>)
350 f(i, std::type_identity<T>{});
351 else if constexpr (std::is_invocable_v<FUNC, std::type_identity<T>, size_t>)
352 f(std::type_identity<T>{}, i);
353 else
354 f(std::type_identity<T>{});
355 }(Idxs, std::type_identity<ARGS>{}), ...);
356 }(std::make_index_sequence<sizeof...(ARGS)>{});
357 }
358 */
359
360 namespace detail
361 {
362 /*
363 template<typename T, typename FUNC, size_t... Is>
364 void do_for_each_in_tuple(T&& t, FUNC f, std::index_sequence<Is...>)
365 {
366 if constexpr (std::is_invocable_v<FUNC, size_t, std::type_identity<T>>)
367 (f(Is, std::get<Is>(t)), ...);
368 else if constexpr (std::is_invocable_v<FUNC, std::type_identity<T>, size_t>)
369 (f(std::get<Is>(t), Is), ...);
370 else
371 (f(std::get<Is>(t)), ...);
372 }
373
374 template<typename ARGS, size_t Is, typename FUNC>
375 void do_for_each(FUNC f)
376 {
377 if constexpr (std::is_invocable_v<FUNC, size_t, std::type_identity<ARGS>>)
378 (f(std::integral_constant<size_t, Is>, std::type_identity<ARGS>{}), ...);
379 else if constexpr (std::is_invocable_v<FUNC, std::type_identity<ARGS>, size_t>)
380 (f(std::type_identity<ARGS>{}, std::integral_constant<size_t, Is>), ...);
381 else
382 (f(std::type_identity<ARGS>{}), ...);
383 }
384
385 template<typename ARGS, size_t Is, typename FUNC>
386 void do_for_each(FUNC f)
387 {
388 if constexpr (std::is_invocable_v<FUNC, size_t, std::type_identity<ARGS>>)
389 (f(std::integral_constant<size_t, Is>, std::type_identity<ARGS>{}), ...);
390 else if constexpr (std::is_invocable_v<FUNC, std::type_identity<ARGS>, size_t>)
391 (f(std::type_identity<ARGS>{}, std::integral_constant<size_t, Is>), ...);
392 else
393 (f(std::type_identity<ARGS>{}), ...);
394 }
395 */
396
397 template <size_t INDEX, typename VALUE, typename FUNC>
398 constexpr void call(VALUE&& value, FUNC&& func)
399 {
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));
412 else
413 func(INDEX);
414 }
415
416 template <size_t INDEX, typename VALUE, typename FUNC>
417 constexpr auto call_r(VALUE&& value, FUNC&& func)
418 {
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));
429 else
430 return func(INDEX);
431 }
432
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...>)
435 {
436 (call<Is>(
437 std::get<Is>(t)
438 , f), ...);
439 }
440
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...>)
443 {
444 return (call_r<Is>(std::get<Is>(t), f) && ...);
445 }
446
447 template<typename T, typename FUNC, size_t... Is>
448 constexpr auto do_transform_tuple(T&& t, FUNC const& f, std::index_sequence<Is...>)
449 {
450 return std::make_tuple(call_r<Is>(
451 std::get<Is>(t)
452 , f)...);
453 }
454
455 template<typename... ARGS, typename FUNC, size_t... Is>
456 constexpr void do_for_each(FUNC const& f, std::index_sequence<Is...>)
457 {
458 (call<Is>(std::type_identity<ARGS>{}, f), ...);
459 }
460 }
461
462 template <typename... ARGS, typename FUNC>
463 constexpr void for_each(FUNC&& f)
464 {
465 detail::do_for_each<ARGS...>(std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>());
466 }
467
468 template<typename... ARGS, typename FUNC>
469 constexpr auto for_each_in_tuple(std::tuple<ARGS...> const& t, FUNC&& f)
470 {
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)>());
473 else
474 detail::do_for_each_in_tuple(t, std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>());
475 }
476
477 template<typename... ARGS, typename FUNC>
478 constexpr auto for_each_in_tuple(std::tuple<ARGS...>&& t, FUNC&& f)
479 {
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)>());
482 else
483 detail::do_for_each_in_tuple(std::move(t), std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>());
484 }
485
486 template<typename... ARGS, typename FUNC>
487 constexpr auto transform_tuple(std::tuple<ARGS...> const& t, FUNC&& f)
488 {
489 return detail::do_transform_tuple(t, std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>());
490 }
491
492 template <typename FUNC, typename... ARGS>
493 constexpr void enumerate_pack(FUNC&& f, ARGS&&... args)
494 {
495 /*
496 [&] <size_t... Idxs>(std::index_sequence<Idxs...>) {
497 ([&] <typename T> (size_t i, T && arg) {
498 if constexpr (std::is_invocable_v<FUNC, T>)
499 f(std::forward<T>(arg));
500 else if constexpr (std::is_invocable_v<FUNC, size_t, T>)
501 f(i, std::forward<T>(arg));
502 else
503 static_assert(!std::is_void_v<T>, "Cannot invoke callback with this type");
504 }(Idxs, std::forward<ARGS>(args)), ...);
505 }(std::make_index_sequence<sizeof...(ARGS)>{});
506 */
507
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)
511 , func), ...);
512 }(std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>{}, std::forward_as_tuple(std::forward<ARGS>(args)...));
513
514
515 //detail::do_enumerate_pack(std::forward<FUNC>(func), std::make_index_sequence<sizeof...(ARGS)>{}, std::forward<ARGS>(args)...);
516 }
517
518 template <size_t I, typename FUNC, typename... ARGS>
519 requires (I < sizeof...(ARGS))
520 constexpr auto apply_to_nth(FUNC&& f, ARGS&&... args)
521 {
522 return [&] <size_t... Idxs>(std::index_sequence<Idxs...>) {
523 return ([&] {
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));
527 else
528 return detail::pass_identity{};
529 }() * ...);
530 }(std::make_index_sequence<sizeof...(args)>{});
531 }
532
533 namespace detail
534 {
535 template <size_t, size_t = detail::not_given, size_t = 1, class = std::integral_constant<size_t, 0>>
536 struct pack_slicer;
537
538 template <size_t Begin, size_t End, size_t Stride, size_t I>
539 struct pack_slicer<Begin, End, Stride, std::integral_constant<size_t, I>>
540 {
541 static constexpr bool include = I >= Begin && I < End && ((I - Begin) % Stride == 0);
542
543 using next = pack_slicer<Begin, End, Stride, std::integral_constant<size_t, I + 1>>;
544
545 template <typename T, typename... ARGS>
546 static constexpr auto make_slice_function(T&& t, ARGS&&... ts)
547 {
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)...); });
552 else
553 return slicer([&cb]<typename... NEW_ARGS>(NEW_ARGS&&... sl) mutable { return cb(std::forward<NEW_ARGS>(sl)...); });
554 };
555 }
556
557 static constexpr auto make_slice_function() { return [](auto&& cb) mutable { return cb(); }; }
558 };
559 }
560
561 template <size_t Begin, size_t End, size_t Stride, double&..., typename FUNC, typename... ARGS>
562 constexpr auto apply_to_slice(FUNC&& callback, ARGS&&... args)
563 {
564 return ::ghassanpl::detail::pack_slicer<Begin, End, Stride>::make_slice_function(std::forward<ARGS>(args)...)(std::forward<FUNC>(callback));
565 }
566
567 template <size_t Begin, size_t End, double&..., typename FUNC, typename... ARGS>
568 constexpr auto apply_to_slice(FUNC&& callback, ARGS&&... args)
569 {
570 return ::ghassanpl::detail::pack_slicer<Begin, End>::make_slice_function(std::forward<ARGS>(args)...)(std::forward<FUNC>(callback));
571 }
572
573 template <size_t Begin, double&..., typename FUNC, typename... ARGS>
574 constexpr auto apply_to_slice(FUNC&& callback, ARGS&&... args)
575 {
576 return ::ghassanpl::detail::pack_slicer<Begin>::make_slice_function(std::forward<ARGS>(args)...)(std::forward<FUNC>(callback));
577 }
578
581}
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.
Definition align+rec2.h:10
constexpr void for_each_pair(FUNC &&f, ARGS &&... args)
Function: for_each_pair TODO: Description.
Definition templates.h:331
constexpr auto transform_tuple(std::tuple< ARGS... > const &t, FUNC &&f)
Function: transform_tuple.
Definition templates.h:487
constexpr void for_each(FUNC &&f)
Function: for_each TODO: Description.
Definition templates.h:463
constexpr auto for_each_in_tuple(std::tuple< ARGS... > const &t, FUNC &&f)
Function: for_each_in_tuple.
Definition templates.h:469
constexpr auto apply_to_slice(FUNC &&f, ARGS &&... args)
Function: apply_to_slice Calls f with a slice of the args pack.
Definition templates.h:562
constexpr void enumerate_pack(FUNC &&f, ARGS &&... args)
Function: enumerate_pack Calls f on every argument args....
Definition templates.h:493
auto is(X const &) -> bool
Shamelessly stolen from hsutter's cppfront.
Definition templates.h:103
constexpr auto apply_to_nth(FUNC &&f, ARGS &&... args)
Function: apply_to_nth Calls f on the Nth argument in the args pack.
Definition templates.h:520
std::variant get index of type
Definition templates.h:190