UgMisc 0.2-110
Miscellaneous C++ header library
Loading...
Searching...
No Matches
typelist.hpp
Go to the documentation of this file.
1/*
2 * SPDX-Licence-Identifier: MIT
3 *
4 * Copyright 2025 Larry Chips
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the “Software”), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef UGMISC_TYPELIST_HPP
25#define UGMISC_TYPELIST_HPP
26
27#include <cstddef>
28#include <type_traits>
29#include <utility>
30
31
61
62
63
64
65namespace ugmisc {
66
67
73
74
75/* *****************************************************************************
76 *
77 * ugmisc::typelist_ namespace contains implementation details
78 *
79 *
80 * Forward declarations in ugmisc namespace are first.
81 *
82 * Then forward declarations in ugmisc::typelist_ namespace.
83 *
84 * Then template type alias declarations in ugmisc follow.
85 *
86 * Then class template definitions.
87 *
88 *
89 * Using this order allows classes like instances of type_list to have methods
90 * which use the template type aliases. The methods can then be used for
91 * convenience by the user.
92 *
93 * ****************************************************************************/
94
95// Forwards in ugmisc.
97template<class...> struct concatenate_type_lists;
99template<class...> struct flatten;
105template<class T> struct get_as_list;
106template<std::size_t, std::size_t, class> struct get_type_list_sublist;
108template<class> struct is_type_list;
109template<class...> struct type_list;
110template<class> struct unwrap;
111template<class> struct wrapped_list;
112
113// Forwards in ugmisc::typelist_.
115namespace typelist_ {
116template<template<class> class, class> struct apply_each;
117template<template<class> class, class, test_modifier>
118 struct filter_type_list;
119template<std::size_t, class> struct get_type_list_member;
120template<std::ptrdiff_t, std::ptrdiff_t, std::size_t, class>
121 struct type_list_stride;
122} /* typelist_ (ugmisc::typelist_) */
124
125
149template<class...T>
151
152
154template<class T> using get_as_list_t = typename get_as_list<T>::type;
155
156
157template<class T> static constexpr bool is_type_list_v = is_type_list<T>::value;
158
159
160template<class...T> static constexpr bool are_type_lists_v = (... && is_type_list_v<T>);
161
162
163
164
172template<std::size_t I, class T> using type_list_member =
173 typename typelist_::get_type_list_member<I, T>::type;
174
175
176
177
200template<class...T> using flatten_t = typename flatten<T...>::type;
201
202
203
204
213template<std::size_t From, std::size_t To, class T>
214using type_list_sublist = typename get_type_list_sublist<From, To, T>::type;
215
219template<std::size_t From, std::size_t Count, class T>
221
228template<std::size_t Count, class T>
230
237template<std::size_t Count, class T>
238using type_list_suffix = type_list_sublist<T::size - Count, T::size, T>;
239
246template<std::size_t Count, class T>
248
255template<std::size_t Count, class T>
256using type_list_remove_suffix = type_list_sublist<0, T::size-Count, T>;
257
258
265template<std::size_t From, std::size_t To, class...T>
267
271template<std::size_t From, std::size_t Count, class...T>
273
277template<std::size_t Count, class...T>
279
283template<std::size_t Count, class...T>
285
292template<std::size_t Count, class...T>
294
301template<std::size_t Count, class...T>
303
304
305
306
321template<
322 template<class> class Test,
323 class T,
325 >
327 typename typelist_::filter_type_list<Test, T, Mod>::type;
328
329
334template<
335 template<class> class Test,
336 class T,
337 test_modifier Mod = static_cast<test_modifier>(0)
338 >
340
341
342
343
350template< template<class> class F, class T >
351using type_list_apply_each_class = typename typelist_::apply_each<F, T>::class_types;
352
353
360template< template<class> class F, class T >
361using type_list_apply_each = typename typelist_::apply_each<F, T>::inner_types;
362
363
371template< template<class> class F, class...T >
373
374
381template< template<class> class F, class...T >
383
384
388template<
389 template<class> class Test,
390 test_modifier Mod,
391 class...T
392 >
393using flatten_filter = type_list_filter<Test, flatten_t<T...>, Mod>;
394
395
396
397
448template<
449 std::ptrdiff_t Base,
450 std::ptrdiff_t Stride,
451 std::size_t Count,
452 class T
453 >
455 typename typelist_::type_list_stride<Base, Stride, Count, T>::type;
456
457
462template<
463 std::ptrdiff_t Base,
464 std::ptrdiff_t Stride,
465 std::size_t Count,
466 class...T
467 >
468using flatten_stride = type_list_stride<Base, Stride, Count, flatten_t<T...>>;
469
470
471
473namespace typelist_ {
474
475template<std::size_t I, class T> struct get_type_list_member {};
476
477template<std::size_t I, class T1, class...T>
478struct get_type_list_member<I, type_list<T1, T...>> {
479 static_assert( I < sizeof...(T) + 1, "Index out of range" );
480 using type = typename get_type_list_member<I-1, type_list<T...>>::type;
481};
482
483template<class T1, class...T> struct get_type_list_member<0, type_list<T1, T...>> {
484 using type = T1;
485};
486
487
488
489
490template<template <class> class Test, class T, test_modifier Mod>
491struct filter_type_list {
492};
493
494
495template<template<class> class Test, test_modifier Mod>
496struct filter_type_list<Test, type_list<>, Mod> {
497 using type = type_list<>;
498};
499
500
501template<template <class> class Test, class T, test_modifier Mod>
502struct filter_type_list<Test, type_list<T>, Mod> {
503 using type = std::conditional_t<
504 Test<T>::value != (Mod == invert_test),
507 >;
508};
509
510
511template<template<class> class Test, test_modifier Mod, class T1, class T2, class...Ts>
512struct filter_type_list<Test, type_list<T1, T2, Ts...>, Mod> {
513private:
514 using all = type_list<T1, T2, Ts...>;
515 static constexpr std::size_t halfway = all::size / 2;
516 using first_half = type_list_prefix<halfway, all>;
517 using second_half = type_list_remove_prefix<halfway, all>;
518
519public:
520 using type = concatenate_type_lists_t<
523 >;
524};
525
526
527template< template<class> class F, class...T >
528struct apply_each<F, type_list<T...>> {
529 using class_types = type_list<F<T>...>;
530 using inner_types = type_list<typename F<T>::type...>;
531};
532
533
534
535
536/*
537 * Used by type_list_stride specialisations. Instantiating one of these
538 * asserts that the stride array doesn't go out of the bounds of the underlying
539 * array.
540 */
541template<
542 std::ptrdiff_t SignedBase,
543 std::ptrdiff_t Stride,
544 std::size_t Count,
545 class T
546 >
547struct type_list_stride_params {
548
549 static_assert( is_type_list_v< T > );
550
551 static constexpr std::size_t Base =
552 (std::size_t)(SignedBase >= 0 ? SignedBase : T::size + SignedBase);
553
554
555 template<std::size_t new_index, bool check = true>
556 static constexpr std::size_t original_index() {
557 static_assert( (!check) || new_index < Count );
558 const std::ptrdiff_t base = Base;
559 return base + ((std::ptrdiff_t)new_index) * Stride;
560 }
561
562
563 template<std::size_t original_index, bool check = true>
564 static constexpr std::size_t new_index() {
565 /*
566 * original_index Io
567 * new_index In
568 * base B
569 * stride S
570 *
571 * Io = B + In*S
572 * In = (Io - B)/S
573 */
574
575 constexpr std::ptrdiff_t dist = ((std::ptrdiff_t)original_index) - Base;
576 constexpr std::ptrdiff_t new_index_signed = dist/Stride;
577 constexpr std::ptrdiff_t new_index_mod = dist%Stride;
578 constexpr std::size_t new_index = (std::size_t)new_index_signed;
579
580 static_assert(
581 (!check) || (new_index >= T::size),
582 "Index out of underlying array bounds."
583 );
584
585 static_assert(
586 (!check) || (original_index >= Count),
587 "Index out of stride array bounds."
588 );
589
590 static_assert(
591 (!check) || (new_index_mod == 0),
592 "Index not touched by the stride array."
593 );
594
595 return new_index;
596 }
597
598
599 // original_index() returns an unsigned index, so we don't need a lower
600 // bound check here.
601 static_assert(
602 Count == 0 || original_index<Count - 1, false>() < T::size,
603 "type_list_stride out of bounds."
604 );
605};
606
607
608
609
610template<
611 std::ptrdiff_t Base,
612 std::ptrdiff_t Stride,
613 std::size_t Count,
614 class T
615 >
616struct type_list_stride {
617private:
618 using params = type_list_stride_params<Base, Stride, Count, T>;
619
620 template<class S> struct deduce_type;
621
622 template<std::size_t...N> struct deduce_type<std::index_sequence<N...>> {
623 using type = ::ugmisc::type_list<
625 >;
626 };
627
628public:
629 using type = typename deduce_type< std::make_index_sequence<Count> >::type;
630};
631
632
633
634} // ugmisc::typelist_
636
637
638
639
640template<class T> struct is_type_list : public std::false_type {};
641
642template<class...T> struct is_type_list<type_list<T...>> : std::true_type {};
643
644
645
646
647template<> struct concatenate_type_lists<> {
648 using type = type_list<>;
649};
650
651
652template<class...T> struct concatenate_type_lists<type_list<T...>> {
653 using type = type_list<T...>;
654};
655
656
657template<class T1, class T2, class T3, class...Ts> struct concatenate_type_lists<T1, T2, T3, Ts...> {
658 static_assert( are_type_lists_v<T1, T2, T3, Ts...> );
659 using type = typename concatenate_type_lists<
660 typename concatenate_type_lists<T1, T2>::type,
661 typename concatenate_type_lists<T3, Ts...>::type
662 >::type;
663};
664
665
666template<class T, class...Ts>
667struct concatenate_type_lists< T, type_list<Ts...> >
668{
669 static_assert( is_type_list_v<T> );
670 using type = typename T::template append<Ts...>;
671};
672
673
674
675
676/*
677 * TODO: Reimplement sublists as a special case of strides.
678 */
679template<std::size_t From, class...T>
680struct get_type_list_sublist<From, From, type_list<T...>> {
681 static_assert( From <= sizeof...(T) );
682 using type = type_list<>;
683};
684
685template<std::size_t From, class...T>
686struct get_type_list_sublist<From, From+1, type_list<T...>> {
687 static_assert( From < sizeof...(T) );
688 using type =
689 type_list< type_list_member<From, type_list<T...>> >;
690};
691
692template<std::size_t From, std::size_t To, class...T>
693struct get_type_list_sublist<From, To, type_list<T...>> {
694private:
695 static_assert( To >= From, "Invalid range: To must be no less than From." );
696 static_assert( To > From+1, "Logic error. Wrong partial specialisation." );
697
698 using list = type_list<T...>;
699
700 static constexpr std::size_t from1 = From;
701 static constexpr std::size_t to1 = From + (To - From)/2;
702 static constexpr std::size_t from2 = to1;
703 static constexpr std::size_t to2 = To;
704
705 using part1 = typename get_type_list_sublist<from1, to1, list>::type;
706 using part2 = typename get_type_list_sublist<from2, to2, list>::type;
707
708public:
709 using type = concatenate_type_lists_t< part1, part2 >;
710};
711
712
713/*
714 * This is deprecated.
715 * Use get_type_list_sublist instead.
716 */
717template<std::size_t From, std::size_t To, class T>
718struct get_type_list_slice : public get_type_list_sublist<From, To, T> {};
719
720
721
722
732template<class T> struct wrapped_list {
733 static_assert(
734 false,
735 "wrapped_list must wrap a wrapped_list or a type_list"
736 );
737};
738
739
740template<class...T> struct wrapped_list<type_list<T...>> {
741 using type = type_list<T...>;
742};
743
744
745template<class T> struct wrapped_list<wrapped_list<T>> {
746 using type = wrapped_list<T>;
747};
748
749
750
751
752template<class T> struct get_as_list {
753 using type = type_list<T>;
754};
755
756
757template<class...T> struct get_as_list<type_list<T...>> {
758 using type = type_list<T...>;
759};
760
761
762// This has never been used or documented.
763template<class T> struct unwrap {
764 using type = T;
765};
766
767
768template<class T> struct unwrap<wrapped_list<T>> {
769 using type = T;
770};
771
772
773template<class...T> struct flatten {
774 // Every flatten special defs a type_list type. The generic one
775 // concatenates the lists created from each tparam.
777};
778
779
780/*
781 * A single type which is not a type_list or wrapped_list is simply put into a
782 * type_list.
783 */
784template<class T> struct flatten<T> {
785 using type = type_list<T>;
786};
787
788
789/*
790 * A type list needs unwrapping recursively, so we flatten each of the member
791 * types.
792 */
793template<class...T> struct flatten< type_list<T...> > {
794 using type = concatenate_type_lists_t<typename flatten<T>::type...>;
795};
796
797
798/*
799 * A wrapped_list is unwrapped once, then the content put into a list.
800 */
801template<class T> struct flatten< wrapped_list<T> > {
802 using type = type_list<T>; // Note the lack of recursion here.
803};
804
805
806
807
811template<class...T> struct type_list {
813 static constexpr std::size_t size = sizeof...(T);
814
816 template<template<class...> class Templ> using apply_t = Templ<T...>;
817
823 template<template<class...> class Templ> using apply = apply_t<Templ>;
824
829 template<template<class...> class Templ> using call_t =
830 typename Templ<T...>::type;
831
837 template<template<class...> class Templ> using call = call_t<Templ>;
838
842 template<class...U>
843 using prepend_t = type_list<U..., T...>;
844
850 template<class...U> using prepend = prepend_t<U...>;
851
855 template<class...U>
856 using append_t = type_list<T..., U...>;
857
863 template<class...U> using append = append_t<U...>;
864
874 template<std::size_t From, std::size_t To>
876
880 template<
881 std::ptrdiff_t Base,
882 std::ptrdiff_t Stride,
883 std::size_t Count
884 >
886
892 template<
893 std::ptrdiff_t Base,
894 std::ptrdiff_t Stride,
895 std::size_t Count
896 >
898};
899
900
901
902
911template<class T, class U>
912constexpr auto operator + (T, U) -> concatenate_type_lists_t<T, U> {
913 return {};
914}
915
916
917} /* ::ugmisc */
918
919#endif /* UGMISC_TYPELIST_HPP */
Definition typelist.hpp:97
Definition typelist.hpp:773
Definition typelist.hpp:752
Definition typelist.hpp:640
Encapsulates a list of types.
Definition typelist.hpp:811
prepend_t< U... > prepend
Definition typelist.hpp:850
type_list< T..., U... > append_t
Definition typelist.hpp:856
type_list_stride< Base, Stride, Count, type_list > stride_t
Definition typelist.hpp:885
append_t< U... > append
Definition typelist.hpp:863
typename Templ< T... >::type call_t
Definition typelist.hpp:829
apply_t< Templ > apply
Definition typelist.hpp:823
type_list_sublist< From, To, type_list > sublist_t
Definition typelist.hpp:875
type_list< U..., T... > prepend_t
Definition typelist.hpp:843
call_t< Templ > call
Definition typelist.hpp:837
static constexpr std::size_t size
Definition typelist.hpp:813
stride_t< Base, Stride, Count > stride
Definition typelist.hpp:897
Templ< T... > apply_t
Definition typelist.hpp:816
Definition typelist.hpp:732
type_list_sized_sublist< From, Count, flatten_t< T... > > flatten_sized_sublist
Definition typelist.hpp:272
type_list_sublist< 0, Count, T > type_list_prefix
Definition typelist.hpp:229
type_list_sublist< From, To, flatten_t< T... > > flatten_sublist
Definition typelist.hpp:266
typename get_as_list< T >::type get_as_list_t
Definition typelist.hpp:154
typename typelist_::type_list_stride< Base, Stride, Count, T >::type type_list_stride
Definition typelist.hpp:454
typename typelist_::apply_each< F, T >::class_types type_list_apply_each_class
Definition typelist.hpp:351
type_list_filter< Test, T, Mod > filter_type_list
Definition typelist.hpp:339
type_list_sublist< 0, T::size-Count, T > type_list_remove_suffix
Definition typelist.hpp:256
type_list_filter< Test, flatten_t< T... >, Mod > flatten_filter
Definition typelist.hpp:393
type_list_remove_prefix< Count, flatten_t< T... > > flatten_remove_prefix
Definition typelist.hpp:293
typename typelist_::filter_type_list< Test, T, Mod >::type type_list_filter
Definition typelist.hpp:326
test_modifier
Definition typelist.hpp:69
@ invert_test
Keep types when the Filter returns false.
Definition typelist.hpp:71
@ no_invert_test
Keep types when the Filter returns true.
Definition typelist.hpp:70
type_list_sublist< T::size - Count, T::size, T > type_list_suffix
Definition typelist.hpp:238
typename typelist_::apply_each< F, T >::inner_types type_list_apply_each
Definition typelist.hpp:361
typename flatten< T... >::type flatten_t
Converts the template parameters into a type_list.
Definition typelist.hpp:200
type_list_prefix< Count, flatten_t< T... > > flatten_prefix
Definition typelist.hpp:278
type_list_sublist< From, From+Count, T > type_list_sized_sublist
Definition typelist.hpp:220
type_list_remove_suffix< Count, flatten_t< T... > > flatten_remove_suffix
Definition typelist.hpp:302
typename concatenate_type_lists< T... >::type concatenate_type_lists_t
Definition typelist.hpp:150
type_list_apply_each< F, flatten_t< T... > > flatten_apply_each
Definition typelist.hpp:382
type_list_stride< Base, Stride, Count, flatten_t< T... > > flatten_stride
Definition typelist.hpp:468
type_list_suffix< Count, flatten_t< T... > > flatten_suffix
Definition typelist.hpp:284
type_list_sublist< Count, T::size, T > type_list_remove_prefix
Definition typelist.hpp:247
type_list_apply_each_class< F, flatten_t< T... > > flatten_apply_each_class
Definition typelist.hpp:372
typename typelist_::get_type_list_member< I, T >::type type_list_member
Definition typelist.hpp:172
typename get_type_list_sublist< From, To, T >::type type_list_sublist
Definition typelist.hpp:214