header_utils
Loading...
Searching...
No Matches
templates.h
1
4
5#pragma once
6
7#include <tuple>
8#include <variant>
9#include <optional>
10#include <any>
11
12#include "cpp23.h"
13
14#if !defined(__cpp_concepts)
15#error "This library requires concepts"
16#endif
17
20namespace ghassanpl
21{
22 template<size_t I, typename... Ts>
23 using nth_type_of = std::tuple_element_t<I, std::tuple<Ts...>>;
24 template<typename... Ts>
25 using first_type_of = std::tuple_element_t<0, std::tuple<Ts...>>;
26 template<typename... Ts>
27 using last_type_of = std::tuple_element_t<(sizeof...(Ts) - 1), std::tuple<Ts...>>;
28
29 template <size_t I, typename T, typename... Ts>
30 auto nth_value_of(T&& t, Ts&&... args)
31 {
32 if constexpr (I == 0)
33 return std::forward<T>(t);
34 else
35 {
36 using return_type = typename nth_type_of<I, T, Ts...>::type;
37 return std::forward<return_type>(nth_value_of<I - 1>((std::forward<Ts>(args))...));
38 }
39 }
40
41 template <typename... Ts>
42 auto first_value_of(Ts&&... args)
43 {
44 using return_type = typename first_type_of<Ts...>::type;
45 return std::forward<return_type>(nth_value_of<0>((std::forward<Ts>(args))...));
46 }
47
48 template <typename... Ts>
49 auto last_value_of(Ts&&... args)
50 {
51 using return_type = typename last_type_of<Ts...>::type;
52 return std::forward<return_type>(nth_value_of<sizeof...(Ts) - 1>((std::forward<Ts>(args))...));
53 }
54
55
56
59 template <typename... ARGS, typename FUNC>
60 constexpr void for_each(FUNC&& f);
61
64 template <typename FUNC, typename... ARGS>
65 requires ((sizeof...(ARGS) % 2) == 0)
66 constexpr void for_each_pair(FUNC&& f, ARGS&&... args);
67
69 template<typename... ARGS, typename FUNC>
70 constexpr void for_each_in_tuple(std::tuple<ARGS...> const& t, FUNC&& f);
71
73 template<typename... ARGS, typename FUNC>
74 constexpr auto transform_tuple(std::tuple<ARGS...> const& t, FUNC&& f);
75
79 template <typename FUNC, typename... ARGS>
80 constexpr void enumerate_pack(FUNC&& f, ARGS&&... args);
81
84 template <size_t N, typename FUNC, typename... ARGS>
85 requires (N < sizeof...(ARGS))
86 constexpr auto apply_to_nth(FUNC&& f, ARGS&&... args);
87
90 template <size_t Begin, size_t End, size_t Stride, double&..., typename FUNC, typename... ARGS>
91 constexpr auto apply_to_slice(FUNC&& f, ARGS&&... args);
92
95 template <size_t Begin, size_t End, double&..., typename FUNC, typename... ARGS>
96 constexpr auto apply_to_slice(FUNC&& f, ARGS&&... args);
97
100 template <size_t Begin, double&..., typename FUNC, typename... ARGS>
101 constexpr auto apply_to_slice(FUNC&& f, ARGS&&... args);
102
103
105 template< typename C, typename X >
106 auto is(X const&) -> bool {
107 return false;
108 }
109
110 template< typename C, typename X >
111 requires std::is_same_v<C, X>
112 auto is(X const&) -> bool {
113 return true;
114 }
115
116 template< typename C, typename X >
117 requires (std::is_base_of_v<C, X> && !std::is_same_v<C, X>)
118 auto is(X const&) -> bool {
119 return true;
120 }
121
122 template< typename C, typename X >
123 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
124 auto is(X const& x) -> bool {
125 return dynamic_cast<C const*>(&x) != nullptr;
126 }
127
128 template< typename C, typename X >
129 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
130 auto is(X const* x) -> bool {
131 return dynamic_cast<C const*>(x) != nullptr;
132 }
133
134 template< typename C, typename X >
135 requires dereferenceable<X> && std::is_default_constructible_v<X> && std::is_same_v<C, void>
136 auto is(X const& x) -> bool
137 {
138 return x == X();
139 }
140
141 template< typename C >
142 auto as(...) -> auto {
143 return nullptr;
144 }
145
146 template< typename C, typename X >
147 requires std::is_same_v<C, X>
148 auto as(X const& x) -> auto&& {
149 return x;
150 }
151
152 template< typename C, typename X >
153 auto as(X const& x) -> auto
154 requires (!std::is_same_v<C, X> && std::constructible_from<C, X const&>)
155 {
156 return C{ x };
157 }
158
159 template< typename C, typename X >
160 requires std::is_base_of_v<C, X>
161 auto as(X&& x) -> C&& {
162 return std::forward<X>(x);
163 }
164
165 template< typename C, typename X >
166 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
167 auto as(X& x) -> C& {
168 return dynamic_cast<C&>(x);
169 }
170
171 template< typename C, typename X >
172 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
173 auto as(X const& x) -> C const& {
174 return dynamic_cast<C const&>(x);
175 }
176
177 template< typename C, typename X >
178 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
179 auto as(X* x) -> C* {
180 return dynamic_cast<C*>(x);
181 }
182
183 template< typename C, typename X >
184 requires (std::is_base_of_v<X, C> && !std::is_same_v<C, X>)
185 auto as(X const* x) -> C const* {
186 return dynamic_cast<C const*>(x);
187 }
188
189
191
192 template <typename T, typename>
193 struct get_index;
194
195 template <size_t I, typename... Ts>
196 struct get_index_impl : std::integral_constant<size_t, (size_t)-1>
197 {
198 //static_assert((std::is_same_v<size_t, Ts> && ...), "type not a member");
199 };
200
201 template <size_t I, typename T, typename... Ts>
202 struct get_index_impl<I, T, T, Ts...>
203 : std::integral_constant<size_t, I>
204 { };
205
206 template <size_t I, typename T, typename U, typename... Ts>
207 struct get_index_impl<I, T, U, Ts...>
208 : get_index_impl<I + 1, T, Ts...>
209 { };
210
211 template <typename T, typename... Ts>
212 struct get_index<T, std::variant<Ts...>>
213 : get_index_impl<0, T, Ts...>
214 { };
215
216 template <typename T, typename... Ts>
217 struct get_index<T, std::tuple<Ts...>>
218 : get_index_impl<0, T, Ts...>
219 { };
220
221
222 template <typename TYPE, typename TYPE_CONTAINER>
223 inline constexpr size_t get_index_v = get_index<TYPE, TYPE_CONTAINER>::value;\
224
225 template <typename TYPE, typename TYPE_CONTAINER>
226 inline constexpr bool has_type_v = get_index<TYPE, TYPE_CONTAINER>::value != (size_t)-1;
227
228
229 //-------------------------------------------------------------------------------------------------------------
230 // std::variant is and as
231 //
232
233 template<typename T, typename... Ts>
234 auto is(std::variant<Ts...> const& x)
235 {
236 if constexpr (std::is_same_v<T, void>)
237 {
238 if (x.valueless_by_exception()) return true;
239 if constexpr (is_any_of_v<std::monostate, Ts...>)
240 return std::get_if<std::monostate>(&x) != nullptr;
241 }
242 return get_index_v<T, std::variant<Ts...>> == x.index();
243 }
244
245 template<typename T, typename... Ts>
246 auto as(std::variant<Ts...> const& x)
247 {
248 return std::get<T>(x);
249 }
250
251 //-------------------------------------------------------------------------------------------------------------
252 // std::any is and as
253 //
254 template<typename T, typename X>
255 requires (std::is_same_v<X, std::any> && !std::is_same_v<T, std::any> && !std::is_same_v<T, void>)
256 constexpr auto is(X const& x) -> bool
257 {
258 return x.type() == typeid(T);
259 }
260
261 template<typename T, typename X>
262 requires (std::is_same_v<X, std::any> && std::is_same_v<T, void>)
263 constexpr auto is(X const& x) -> bool
264 {
265 return !x.has_value();
266 }
267
268 template<typename T, typename X>
269 requires (!std::is_reference_v<T> && std::is_same_v<X, std::any> && !std::is_same_v<T, std::any>)
270 constexpr auto as(X const& x) -> T
271 {
272 return std::any_cast<T>(x);
273 }
274
275
276 //-------------------------------------------------------------------------------------------------------------
277 // std::optional is and as
278 //
279 template<typename T, typename X>
280 requires std::is_same_v<X, std::optional<T>>
281 constexpr auto is(X const& x) -> bool
282 {
283 return x.has_value();
284 }
285
286 template<typename T, typename U>
287 requires std::is_same_v<T, void>
288 constexpr auto is(std::optional<U> const& x) -> bool
289 {
290 return !x.has_value();
291 }
292
293 template<typename T, typename X>
294 requires std::is_same_v<X, std::optional<T>>
295 constexpr auto as(X const& x) -> auto&&
296 {
297 return x.value();
298 }
299
300}
301
302namespace ghassanpl
303{
304
305 namespace detail
306 {
307 struct pass_identity
308 {
309 template <typename T>
310 requires (!std::is_same_v<T, pass_identity>)
311 T operator* (T&& obj) const { return std::forward<T>(obj); }
312
313 pass_identity operator* (pass_identity&&) const { return {}; }
314 };
315
316 template <typename T>
317 requires (!std::is_same_v<T, pass_identity>)
318 T operator* (T&& obj, pass_identity&& p) { return std::forward<T>(obj); }
319
320 constexpr size_t not_given = std::numeric_limits<size_t>::max();
321 }
322
323 template <typename FUNC, typename... ARGS>
324 requires ((sizeof...(ARGS) % 2) == 0)
325 constexpr void for_each_pair(FUNC&& f, ARGS&&... args)
326 {
327 if constexpr (sizeof...(args) > 1)
328 {
329 [&]<typename T1, typename T2, typename... NEW_ARGS>(T1 && t1, T2 && t2, NEW_ARGS&&... new_args) {
330 f(std::forward<T1>(t1), std::forward<T2>(t2));
331 if constexpr (sizeof...(args) > 1)
332 for_each_pair(f, std::forward<NEW_ARGS>(new_args)...);
333 }(std::forward<ARGS>(args)...);
334 }
335 }
336
337 /*
338 template <typename... ARGS, typename FUNC>
339 constexpr void for_each(FUNC&& f)
340 {
341 [&] <size_t... Idxs>(std::index_sequence<Idxs...>) {
342 ([&] <typename T> (size_t i, std::type_identity<T>) {
343 if constexpr (std::is_invocable_v<FUNC, size_t, std::type_identity<T>>)
344 f(i, std::type_identity<T>{});
345 else if constexpr (std::is_invocable_v<FUNC, std::type_identity<T>, size_t>)
346 f(std::type_identity<T>{}, i);
347 else
348 f(std::type_identity<T>{});
349 }(Idxs, std::type_identity<ARGS>{}), ...);
350 }(std::make_index_sequence<sizeof...(ARGS)>{});
351 }
352 */
353
354 namespace detail
355 {
356 /*
357 template<typename T, typename FUNC, size_t... Is>
358 void do_for_each_in_tuple(T&& t, FUNC f, std::index_sequence<Is...>)
359 {
360 if constexpr (std::is_invocable_v<FUNC, size_t, std::type_identity<T>>)
361 (f(Is, std::get<Is>(t)), ...);
362 else if constexpr (std::is_invocable_v<FUNC, std::type_identity<T>, size_t>)
363 (f(std::get<Is>(t), Is), ...);
364 else
365 (f(std::get<Is>(t)), ...);
366 }
367
368 template<typename ARGS, size_t Is, typename FUNC>
369 void do_for_each(FUNC f)
370 {
371 if constexpr (std::is_invocable_v<FUNC, size_t, std::type_identity<ARGS>>)
372 (f(std::integral_constant<size_t, Is>, std::type_identity<ARGS>{}), ...);
373 else if constexpr (std::is_invocable_v<FUNC, std::type_identity<ARGS>, size_t>)
374 (f(std::type_identity<ARGS>{}, std::integral_constant<size_t, Is>), ...);
375 else
376 (f(std::type_identity<ARGS>{}), ...);
377 }
378
379 template<typename ARGS, size_t Is, typename FUNC>
380 void do_for_each(FUNC f)
381 {
382 if constexpr (std::is_invocable_v<FUNC, size_t, std::type_identity<ARGS>>)
383 (f(std::integral_constant<size_t, Is>, std::type_identity<ARGS>{}), ...);
384 else if constexpr (std::is_invocable_v<FUNC, std::type_identity<ARGS>, size_t>)
385 (f(std::type_identity<ARGS>{}, std::integral_constant<size_t, Is>), ...);
386 else
387 (f(std::type_identity<ARGS>{}), ...);
388 }
389 */
390
391 template <size_t INDEX, typename VALUE, typename FUNC>
392 constexpr void call(VALUE&& value, FUNC&& func)
393 {
394 if constexpr (std::is_invocable_v<FUNC, std::integral_constant<size_t, INDEX>, VALUE>)
395 func(std::integral_constant<size_t, INDEX>{}, std::forward<VALUE>(value));
396 else if constexpr (std::is_invocable_v<FUNC, VALUE, std::integral_constant<size_t, INDEX>>)
397 func(std::forward<VALUE>(value), std::integral_constant<size_t, INDEX>{});
398 else if constexpr (std::is_invocable_v<FUNC, VALUE, size_t>)
399 func(std::forward<VALUE>(value), INDEX);
400 else if constexpr (std::is_invocable_v<FUNC, size_t, VALUE>)
401 func(INDEX, std::forward<VALUE>(value));
402 else if constexpr (std::is_invocable_v<FUNC, VALUE>)
403 func(std::forward<VALUE>(value));
404 else
405 func(INDEX);
406 }
407
408 template <size_t INDEX, typename VALUE, typename FUNC>
409 constexpr auto call_r(VALUE&& value, FUNC&& func)
410 {
411 if constexpr (std::is_invocable_v<FUNC, std::integral_constant<size_t, INDEX>, VALUE>)
412 return func(std::integral_constant<size_t, INDEX>{}, std::forward<VALUE>(value));
413 else if constexpr (std::is_invocable_v<FUNC, VALUE, std::integral_constant<size_t, INDEX>>)
414 return func(std::forward<VALUE>(value), std::integral_constant<size_t, INDEX>{});
415 else if constexpr (std::is_invocable_v<FUNC, VALUE, size_t>)
416 return func(std::forward<VALUE>(value), INDEX);
417 else if constexpr (std::is_invocable_v<FUNC, size_t, VALUE>)
418 return func(INDEX, std::forward<VALUE>(value));
419 else if constexpr (std::is_invocable_v<FUNC, VALUE>)
420 return func(std::forward<VALUE>(value));
421 else
422 return func(INDEX);
423 }
424
425 template<typename T, typename FUNC, size_t... Is>
426 constexpr void do_for_each_in_tuple(T&& t, FUNC const& f, std::index_sequence<Is...>)
427 {
428 (call<Is>(
429 std::get<Is>(t)
430 , f), ...);
431 }
432
433 template<typename T, typename FUNC, size_t... Is>
434 constexpr auto do_transform_tuple(T&& t, FUNC const& f, std::index_sequence<Is...>)
435 {
436 return std::make_tuple(call_r<Is>(
437 std::get<Is>(t)
438 , f)...);
439 }
440
441 template<typename... ARGS, typename FUNC, size_t... Is>
442 constexpr void do_for_each(FUNC const& f, std::index_sequence<Is...>)
443 {
444 (call<Is>(std::type_identity<ARGS>{}, f), ...);
445 }
446 }
447
448 template <typename... ARGS, typename FUNC>
449 constexpr void for_each(FUNC&& f)
450 {
451 detail::do_for_each<ARGS...>(std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>());
452 }
453
454 template<typename... ARGS, typename FUNC>
455 constexpr void for_each_in_tuple(std::tuple<ARGS...> const& t, FUNC&& f)
456 {
457 detail::do_for_each_in_tuple(t, std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>());
458 }
459
460 template<typename... ARGS, typename FUNC>
461 constexpr void for_each_in_tuple(std::tuple<ARGS...>&& t, FUNC&& f)
462 {
463 detail::do_for_each_in_tuple(std::move(t), std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>());
464 }
465
466 template<typename... ARGS, typename FUNC>
467 constexpr auto transform_tuple(std::tuple<ARGS...> const& t, FUNC&& f)
468 {
469 return detail::do_transform_tuple(t, std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>());
470 }
471
472 template <typename FUNC, typename... ARGS>
473 constexpr void enumerate_pack(FUNC&& f, ARGS&&... args)
474 {
475 /*
476 [&] <size_t... Idxs>(std::index_sequence<Idxs...>) {
477 ([&] <typename T> (size_t i, T && arg) {
478 if constexpr (std::is_invocable_v<FUNC, T>)
479 f(std::forward<T>(arg));
480 else if constexpr (std::is_invocable_v<FUNC, size_t, T>)
481 f(i, std::forward<T>(arg));
482 else
483 static_assert(!std::is_void_v<T>, "Cannot invoke callback with this type");
484 }(Idxs, std::forward<ARGS>(args)), ...);
485 }(std::make_index_sequence<sizeof...(ARGS)>{});
486 */
487
488 []<size_t... INDICES, typename FUNC2, typename TUPLE>(FUNC2 const& func, std::index_sequence<INDICES...>, TUPLE&& tuple) {
489 (detail::call<INDICES>(
490 std::get<INDICES>(tuple)
491 , func), ...);
492 }(std::forward<FUNC>(f), std::make_index_sequence<sizeof...(ARGS)>{}, std::forward_as_tuple(std::forward<ARGS>(args)...));
493
494
495 //detail::do_enumerate_pack(std::forward<FUNC>(func), std::make_index_sequence<sizeof...(ARGS)>{}, std::forward<ARGS>(args)...);
496 }
497
498 template <size_t I, typename FUNC, typename... ARGS>
499 requires (I < sizeof...(ARGS))
500 constexpr auto apply_to_nth(FUNC&& f, ARGS&&... args)
501 {
502 return [&] <size_t... Idxs>(std::index_sequence<Idxs...>) {
503 return ([&] {
504 static_assert(std::is_invocable_v<FUNC, ARGS>, "Cannot invoke callback with this type");
505 if constexpr (Idxs == I)
506 return f(std::forward<ARGS>(args));
507 else
508 return detail::pass_identity{};
509 }() * ...);
510 }(std::make_index_sequence<sizeof...(args)>{});
511 }
512
513 namespace detail
514 {
515 template <size_t, size_t = detail::not_given, size_t = 1, class = std::integral_constant<size_t, 0>>
516 struct pack_slicer;
517
518 template <size_t Begin, size_t End, size_t Stride, size_t I>
519 struct pack_slicer<Begin, End, Stride, std::integral_constant<size_t, I>>
520 {
521 static constexpr bool include = I >= Begin && I < End && ((I - Begin) % Stride == 0);
522
524
525 template <typename T, typename... ARGS>
526 static constexpr auto make_slice_function(T&& t, ARGS&&... ts)
527 {
528 return [slicer = next::make_slice_function(std::forward<ARGS>(ts)...), nt = std::forward<T>(t)]<typename CALLBACK_TYPE>(CALLBACK_TYPE && cb) mutable {
529 if constexpr (include)
531 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)...); });
532 else
533 return slicer([&cb]<typename... NEW_ARGS>(NEW_ARGS&&... sl) mutable { return cb(std::forward<NEW_ARGS>(sl)...); });
534 };
535 }
536
537 static constexpr auto make_slice_function() { return [](auto&& cb) mutable { return cb(); }; }
538 };
539 }
540
541 template <size_t Begin, size_t End, size_t Stride, double&..., typename FUNC, typename... ARGS>
542 constexpr auto apply_to_slice(FUNC&& callback, ARGS&&... args)
543 {
544 return ::ghassanpl::detail::pack_slicer<Begin, End, Stride>::make_slice_function(std::forward<ARGS>(args)...)(std::forward<FUNC>(callback));
545 }
546
547 template <size_t Begin, size_t End, double&..., typename FUNC, typename... ARGS>
548 constexpr auto apply_to_slice(FUNC&& callback, ARGS&&... args)
549 {
550 return ::ghassanpl::detail::pack_slicer<Begin, End>::make_slice_function(std::forward<ARGS>(args)...)(std::forward<FUNC>(callback));
551 }
552
553 template <size_t Begin, double&..., typename FUNC, typename... ARGS>
554 constexpr auto apply_to_slice(FUNC&& callback, ARGS&&... args)
555 {
556 return ::ghassanpl::detail::pack_slicer<Begin>::make_slice_function(std::forward<ARGS>(args)...)(std::forward<FUNC>(callback));
557 }
558
561}
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
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 auto transform_tuple(std::tuple< ARGS... > const &t, FUNC &&f)
Function: transform_tuple.
Definition templates.h:467
constexpr void for_each(FUNC &&f)
Function: for_each TODO: Description.
Definition templates.h:449
constexpr void for_each_pair(FUNC &&f, ARGS &&... args)
Function: for_each_pair TODO: Description.
Definition templates.h:325
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:500
constexpr void for_each_in_tuple(std::tuple< ARGS... > const &t, FUNC &&f)
Function: for_each_in_tuple.
Definition templates.h:455
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:542
constexpr void enumerate_pack(FUNC &&f, ARGS &&... args)
Function: enumerate_pack Calls f on every argument args....
Definition templates.h:473
auto is(X const &) -> bool
Shamelessly stolen from hsutter's cppfront.
Definition templates.h:106
std::variant get index of type
Definition templates.h:193