UgMisc 0.3
Miscellaneous C++ header library
Loading...
Searching...
No Matches
typelist.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: © 2025 Larry Chips <larry@larrychips.net>
3 * SPDX-Licence-Identifier: MIT
4 */
5#ifndef UGMISC_TYPELIST_HPP
6#define UGMISC_TYPELIST_HPP
7
8#include <cstddef>
9#include <limits>
10#include <type_traits>
11#include <utility>
12
13
83
84
85
86
87namespace ugmisc {
88
89
95
96
97/* *****************************************************************************
98 *
99 * ugmisc::typelist_ namespace contains implementation details
100 *
101 *
102 * Forward declarations in ugmisc namespace are first.
103 *
104 * Then forward declarations in ugmisc::typelist_ namespace.
105 *
106 * Then template type alias declarations in ugmisc follow.
107 *
108 * Then class template definitions.
109 *
110 *
111 * Using this order allows classes like instances of type_list to have methods
112 * which use the template type aliases. The methods can then be used for
113 * convenience by the user.
114 *
115 * ****************************************************************************/
116
117// Forwards in ugmisc.
119template<class...> struct concatenate_type_lists;
121template<class...> struct flatten;
127template<class T> struct get_as_list;
128template<std::size_t, std::size_t, class> struct get_type_list_sublist;
130template<class> struct is_type_list;
131template<class...> struct type_list;
132template<class> struct unwrap;
133template<class> struct wrapped_list;
134
135// Forwards in ugmisc::typelist_.
137namespace typelist_ {
138template<template<class> class, class> struct apply_each;
139template<template<class> class, class, test_modifier>
140 struct filter_type_list;
141template<class T> struct get_type_list_from_tparams;
142template<std::size_t, class> struct get_type_list_member;
143template<std::ptrdiff_t, std::ptrdiff_t, std::size_t, class>
144 struct type_list_stride;
145} /* typelist_ (ugmisc::typelist_) */
147
148
172template<class...T>
174
175
177template<class T> using get_as_list_t = typename get_as_list<T>::type;
178
179
180template<class T> static constexpr bool is_type_list_v = is_type_list<T>::value;
181
182
183template<class...T> static constexpr bool are_type_lists_v = (... && is_type_list_v<T>);
184
185
186
187
195template<std::size_t I, class T> using type_list_member =
196 typename typelist_::get_type_list_member<I, T>::type;
197
198
199
200
210template<class T>
212 typename typelist_::get_type_list_from_tparams<T>::type;
213
214
215
216
239template<class...T> using flatten_t = typename flatten<T...>::type;
240
241
242
243
252template<std::size_t From, std::size_t To, class T>
253using type_list_sublist = typename get_type_list_sublist<From, To, T>::type;
254
258template<std::size_t From, std::size_t Count, class T>
260
267template<std::size_t Count, class T>
269
276template<std::size_t Count, class T>
277using type_list_suffix = type_list_sublist<T::size - Count, T::size, T>;
278
285template<std::size_t Count, class T>
287
294template<std::size_t Count, class T>
295using type_list_remove_suffix = type_list_sublist<0, T::size-Count, T>;
296
297
304template<std::size_t From, std::size_t To, class...T>
306
310template<std::size_t From, std::size_t Count, class...T>
312
316template<std::size_t Count, class...T>
318
322template<std::size_t Count, class...T>
324
331template<std::size_t Count, class...T>
333
340template<std::size_t Count, class...T>
342
343
344
345
360template<
361 template<class> class Test,
362 class T,
364 >
366 typename typelist_::filter_type_list<Test, T, Mod>::type;
367
368
373template<
374 template<class> class Test,
375 class T,
376 test_modifier Mod = static_cast<test_modifier>(0)
377 >
379
380
381
382
389template< template<class> class F, class T >
390using type_list_apply_each_class = typename typelist_::apply_each<F, T>::class_types;
391
392
399template< template<class> class F, class T >
400using type_list_apply_each = typename typelist_::apply_each<F, T>::inner_types;
401
402
410template< template<class> class F, class...T >
412
413
420template< template<class> class F, class...T >
422
423
427template<
428 template<class> class Test,
429 test_modifier Mod,
430 class...T
431 >
432using flatten_filter = type_list_filter<Test, flatten_t<T...>, Mod>;
433
434
435
436
487template<
488 std::ptrdiff_t Base,
489 std::ptrdiff_t Stride,
490 std::size_t Count,
491 class T
492 >
494 typename typelist_::type_list_stride<Base, Stride, Count, T>::type;
495
496
501template<
502 std::ptrdiff_t Base,
503 std::ptrdiff_t Stride,
504 std::size_t Count,
505 class...T
506 >
507using flatten_stride = type_list_stride<Base, Stride, Count, flatten_t<T...>>;
508
509
510
512namespace typelist_ {
513
514template<template<class...> class Tmpl, class...T>
515struct get_type_list_from_tparams<Tmpl<T...>> {
516 using type = type_list<T...>;
517};
518
519template<template<class U, U...> class Tmpl, class T, T...V>
520struct get_type_list_from_tparams<Tmpl<T, V...>> {
522};
523
524template<std::size_t I, class T> struct get_type_list_member {};
525
526template<std::size_t I, class T1, class...T>
527struct get_type_list_member<I, type_list<T1, T...>> {
528 static_assert( I < sizeof...(T) + 1, "Index out of range" );
529 using type = typename get_type_list_member<I-1, type_list<T...>>::type;
530};
531
532template<class T1, class...T> struct get_type_list_member<0, type_list<T1, T...>> {
533 using type = T1;
534};
535
536
537
538
539template<template <class> class Test, class T, test_modifier Mod>
540struct filter_type_list {
541};
542
543
544template<template<class> class Test, test_modifier Mod>
545struct filter_type_list<Test, type_list<>, Mod> {
546 using type = type_list<>;
547};
548
549
550template<template <class> class Test, class T, test_modifier Mod>
551struct filter_type_list<Test, type_list<T>, Mod> {
552 using type = std::conditional_t<
553 Test<T>::value != (Mod == invert_test),
556 >;
557};
558
559
560template<template<class> class Test, test_modifier Mod, class T1, class T2, class...Ts>
561struct filter_type_list<Test, type_list<T1, T2, Ts...>, Mod> {
562private:
563 using all = type_list<T1, T2, Ts...>;
564 static constexpr std::size_t halfway = all::size / 2;
565 using first_half = type_list_prefix<halfway, all>;
566 using second_half = type_list_remove_prefix<halfway, all>;
567
568public:
569 using type = concatenate_type_lists_t<
572 >;
573};
574
575
576template< template<class> class F, class...T >
577struct apply_each<F, type_list<T...>> {
578 using class_types = type_list<F<T>...>;
579 using inner_types = type_list<typename F<T>::type...>;
580};
581
582
583
584
585/*
586 * Used by type_list_stride specialisations. Instantiating one of these
587 * asserts that the stride array doesn't go out of the bounds of the underlying
588 * array.
589 */
590template<
591 std::ptrdiff_t SignedBase,
592 std::ptrdiff_t Stride,
593 std::size_t Count,
594 class T
595 >
596struct type_list_stride_params {
597
598 static_assert( is_type_list_v< T > );
599
600 static constexpr std::size_t Base =
601 (std::size_t)(SignedBase >= 0 ? SignedBase : T::size + SignedBase);
602
603
604 template<std::size_t new_index, bool check = true>
605 static constexpr std::size_t original_index() {
606 static_assert( (!check) || new_index < Count );
607 const std::ptrdiff_t base = Base;
608 return base + ((std::ptrdiff_t)new_index) * Stride;
609 }
610
611
612 template<std::size_t original_index, bool check = true>
613 static constexpr std::size_t new_index() {
614 /*
615 * original_index Io
616 * new_index In
617 * base B
618 * stride S
619 *
620 * Io = B + In*S
621 * In = (Io - B)/S
622 */
623
624 constexpr std::ptrdiff_t dist = ((std::ptrdiff_t)original_index) - Base;
625 constexpr std::ptrdiff_t new_index_signed = dist/Stride;
626 constexpr std::ptrdiff_t new_index_mod = dist%Stride;
627 constexpr std::size_t new_index = (std::size_t)new_index_signed;
628
629 static_assert(
630 (!check) || (new_index >= T::size),
631 "Index out of underlying array bounds."
632 );
633
634 static_assert(
635 (!check) || (original_index >= Count),
636 "Index out of stride array bounds."
637 );
638
639 static_assert(
640 (!check) || (new_index_mod == 0),
641 "Index not touched by the stride array."
642 );
643
644 return new_index;
645 }
646
647
648 // original_index() returns an unsigned index, so we don't need a lower
649 // bound check here.
650 static_assert(
651 Count == 0 || original_index<Count - 1, false>() < T::size,
652 "type_list_stride out of bounds."
653 );
654};
655
656
657
658
659template<
660 std::ptrdiff_t Base,
661 std::ptrdiff_t Stride,
662 std::size_t Count,
663 class T
664 >
665struct type_list_stride {
666private:
667 using params = type_list_stride_params<Base, Stride, Count, T>;
668
669 template<class S> struct deduce_type;
670
671 template<std::size_t...N> struct deduce_type<std::index_sequence<N...>> {
672 using type = ::ugmisc::type_list<
674 >;
675 };
676
677public:
678 using type = typename deduce_type< std::make_index_sequence<Count> >::type;
679};
680
681
682
683} // ugmisc::typelist_
685
686
687
688
689template<class T> struct is_type_list : public std::false_type {};
690
691template<class...T> struct is_type_list<type_list<T...>> : std::true_type {};
692
693
694
695
696template<> struct concatenate_type_lists<> {
697 using type = type_list<>;
698};
699
700
701template<class...T> struct concatenate_type_lists<type_list<T...>> {
702 using type = type_list<T...>;
703};
704
705
706template<class T1, class T2, class T3, class...Ts> struct concatenate_type_lists<T1, T2, T3, Ts...> {
707 static_assert( are_type_lists_v<T1, T2, T3, Ts...> );
708 using type = typename concatenate_type_lists<
709 typename concatenate_type_lists<T1, T2>::type,
710 typename concatenate_type_lists<T3, Ts...>::type
711 >::type;
712};
713
714
715template<class T, class...Ts>
716struct concatenate_type_lists< T, type_list<Ts...> >
717{
718 static_assert( is_type_list_v<T> );
719 using type = typename T::template append_t<Ts...>;
720};
721
722
723
724
725/*
726 * TODO: Reimplement sublists as a special case of strides.
727 */
728template<std::size_t From, class...T>
729struct get_type_list_sublist<From, From, type_list<T...>> {
730 static_assert( From <= sizeof...(T) );
731 using type = type_list<>;
732};
733
734template<std::size_t From, class...T>
735struct get_type_list_sublist<From, From+1, type_list<T...>> {
736 static_assert( From < sizeof...(T) );
737 using type =
738 type_list< type_list_member<From, type_list<T...>> >;
739};
740
741template<std::size_t From, std::size_t To, class...T>
742struct get_type_list_sublist<From, To, type_list<T...>> {
743private:
744 static_assert( To >= From, "Invalid range: To must be no less than From." );
745 static_assert( To > From+1, "Logic error. Wrong partial specialisation." );
746
747 using list = type_list<T...>;
748
749 static constexpr std::size_t from1 = From;
750 static constexpr std::size_t to1 = From + (To - From)/2;
751 static constexpr std::size_t from2 = to1;
752 static constexpr std::size_t to2 = To;
753
754 using part1 = typename get_type_list_sublist<from1, to1, list>::type;
755 using part2 = typename get_type_list_sublist<from2, to2, list>::type;
756
757public:
758 using type = concatenate_type_lists_t< part1, part2 >;
759};
760
761
762/*
763 * This is deprecated.
764 * Use get_type_list_sublist instead.
765 */
766template<std::size_t From, std::size_t To, class T>
767struct get_type_list_slice : public get_type_list_sublist<From, To, T> {};
768
769
770
771
781template<class T> struct wrapped_list {
782 static_assert(
783 false,
784 "wrapped_list must wrap a wrapped_list or a type_list"
785 );
786};
787
788
789template<class...T> struct wrapped_list<type_list<T...>> {
790 using type = type_list<T...>;
791};
792
793
794template<class T> struct wrapped_list<wrapped_list<T>> {
795 using type = wrapped_list<T>;
796};
797
798
799
800
801template<class T> struct get_as_list {
802 using type = type_list<T>;
803};
804
805
806template<class...T> struct get_as_list<type_list<T...>> {
807 using type = type_list<T...>;
808};
809
810
811// This has never been used or documented.
812template<class T> struct unwrap {
813 using type = T;
814};
815
816
817template<class T> struct unwrap<wrapped_list<T>> {
818 using type = T;
819};
820
821
822template<class...T> struct flatten {
823 // Every flatten special defs a type_list type. The generic one
824 // concatenates the lists created from each tparam.
826};
827
828
829/*
830 * A single type which is not a type_list or wrapped_list is simply put into a
831 * type_list.
832 */
833template<class T> struct flatten<T> {
834 using type = type_list<T>;
835};
836
837
838/*
839 * A type list needs unwrapping recursively, so we flatten each of the member
840 * types.
841 */
842template<class...T> struct flatten< type_list<T...> > {
843 using type = concatenate_type_lists_t<typename flatten<T>::type...>;
844};
845
846
847/*
848 * A wrapped_list is unwrapped once, then the content put into a list.
849 */
850template<class T> struct flatten< wrapped_list<T> > {
851 using type = type_list<T>; // Note the lack of recursion here.
852};
853
854
855
856
860template<class...T> struct type_list {
861private:
864 template<class, class...>
865 struct stride_support;
866
868 template<class, class...>
869 struct sublist_support;
870
871 template<class...U>
872 using stride_method_return = typename stride_support<void, U...>::type;
873
874 template<class...U>
875 using sublist_method_return = typename sublist_support<void, U...>::type;
877
878public:
880 static constexpr std::size_t size = sizeof...(T);
881
884 template<template<class...> class Templ> using apply_t = Templ<T...>;
885
891 template<template<class...> class Templ> using apply = apply_t<Templ>;
892
897 template<template<class...> class Templ> using call_t =
898 typename Templ<T...>::type;
899
905 template<template<class...> class Templ> using call = call_t<Templ>;
906
910 template<class...U>
911 using prepend_t = type_list<U..., T...>;
912
932 template<class...U> static constexpr prepend_t<U...> prepend(type_list<U...>) { return {}; }
933
937 template<class...U>
938 using append_t = type_list<T..., U...>;
939
959 template<class...U> static constexpr append_t<U...> append(type_list<U...>) { return {}; }
960
970 template<std::size_t From, std::size_t To>
972
986 template< class...U >
987 static constexpr sublist_method_return<U...> sublist(U...) { return {}; }
988
992 template<
993 std::ptrdiff_t Base,
994 std::ptrdiff_t Stride,
995 std::size_t Count
996 >
998
1012 template< class...U >
1013 static constexpr stride_method_return<U...> stride(U...) { return {}; }
1014
1015private:
1018
1019 template<auto V>
1020 struct IgnoreVal {};
1021
1022 /*
1023 * The stride method can take a std::integer_sequence or similar,
1024 * containing the parameters.
1025 */
1026 template< template<class I, I...> class Tmpl, class U, U B, U S, U C >
1027 struct stride_support<
1028 std::enable_if_t< std::numeric_limits<U>::is_integer >,
1029 Tmpl<U, B, S, C>
1030 >
1031 {
1032 using type = stride_t<
1033 (std::ptrdiff_t)B,
1034 (std::ptrdiff_t)S,
1035 (std::size_t)C
1036 >;
1037 };
1038
1039 /*
1040 * The stride method can take each parameter as a std::integral_constant or
1041 * similar: it only has to have a static constexpr integer called "value".
1042 */
1043 template< class B, class S, class C >
1044 struct stride_support<
1045 std::void_t<
1046 std::enable_if_t<
1047 std::numeric_limits<decltype(B::value)>::is_integer
1048 && std::numeric_limits<decltype(S::value)>::is_integer
1049 && std::numeric_limits<decltype(C::value)>::is_integer
1050 >,
1051 IgnoreVal<(std::ptrdiff_t)B::value>, // Ensure value is constexpr,
1052 IgnoreVal<(std::ptrdiff_t)S::value>, // and convertible.
1053 IgnoreVal<(std::size_t)C::value>
1054 >,
1055 B, S, C
1056 >
1057 {
1058 using type = stride_t<
1059 (std::ptrdiff_t)B::value,
1060 (std::ptrdiff_t)S::value,
1061 (std::size_t)C::value
1062 >;
1063 };
1064
1065 /*
1066 * The sublist method can take a std::integer_sequence or similar,
1067 * containing the parameters.
1068 */
1069 template< template<class I, I...> class Tmpl, class U, U From, U To >
1070 struct sublist_support<
1071 std::enable_if_t< std::numeric_limits<U>::is_integer >,
1072 Tmpl<U, From, To>
1073 >
1074 {
1075 using type = sublist_t<
1076 (std::size_t)From,
1077 (std::size_t)To
1078 >;
1079 };
1080
1081 /*
1082 * The sublist method can take each parameter as a std::integral_constant or
1083 * similar: it only has to have a static constexpr integer called "value".
1084 */
1085 template< class From, class To >
1086 struct sublist_support<
1087 std::void_t<
1088 std::enable_if_t<
1089 std::numeric_limits<decltype(From::value)>::is_integer
1090 && std::numeric_limits<decltype(To::value)>::is_integer
1091 >,
1092 IgnoreVal<(std::size_t)From::value>, // Ensure value is constexpr,
1093 IgnoreVal<(std::size_t)To::value> // and convertible.
1094 >,
1095 From, To
1096 >
1097 {
1098 using type = sublist_t<
1099 (std::size_t)From::value,
1100 (std::size_t)To::value
1101 >;
1102 };
1103
1105};
1106
1107
1108
1109
1118template<class T, class U>
1119constexpr auto operator + (T, U) -> concatenate_type_lists_t<T, U> {
1120 return {};
1121}
1122
1123
1127template<class T, class U>
1128constexpr auto operator == (T, U)
1129 -> std::enable_if_t< is_type_list_v<T> && is_type_list_v<U>, bool >
1130{
1131 return std::is_same_v<T, U>;
1132}
1133
1134template<class T, class U>
1135constexpr auto operator != (T, U)
1136 -> std::enable_if_t< is_type_list_v<T> && is_type_list_v<U>, bool >
1137{
1138 return ! std::is_same_v<T, U>;
1139}
1140
1141} /* ::ugmisc */
1142
1143#endif /* UGMISC_TYPELIST_HPP */
Encapsulates a list of types.
Definition typelist.hpp:860
static constexpr append_t< U... > append(type_list< U... >)
Definition typelist.hpp:959
type_list_stride< Base, Stride, Count, type_list > stride_t
Definition typelist.hpp:997
static constexpr stride_method_return< U... > stride(U...)
static constexpr sublist_method_return< U... > sublist(U...)
Definition typelist.hpp:987
type_list_sublist< From, To, type_list > sublist_t
Definition typelist.hpp:971
static constexpr prepend_t< U... > prepend(type_list< U... >)
Definition typelist.hpp:932
type_list_sized_sublist< From, Count, flatten_t< T... > > flatten_sized_sublist
Definition typelist.hpp:311
type_list_sublist< 0, Count, T > type_list_prefix
Definition typelist.hpp:268
type_list_sublist< From, To, flatten_t< T... > > flatten_sublist
Definition typelist.hpp:305
typename get_as_list< T >::type get_as_list_t
Definition typelist.hpp:177
typename typelist_::type_list_stride< Base, Stride, Count, T >::type type_list_stride
Definition typelist.hpp:493
typename typelist_::apply_each< F, T >::class_types type_list_apply_each_class
Definition typelist.hpp:390
type_list_filter< Test, T, Mod > filter_type_list
Definition typelist.hpp:378
type_list_sublist< 0, T::size-Count, T > type_list_remove_suffix
Definition typelist.hpp:295
type_list_filter< Test, flatten_t< T... >, Mod > flatten_filter
Definition typelist.hpp:432
type_list_remove_prefix< Count, flatten_t< T... > > flatten_remove_prefix
Definition typelist.hpp:332
typename typelist_::filter_type_list< Test, T, Mod >::type type_list_filter
Definition typelist.hpp:365
typename typelist_::get_type_list_from_tparams< T >::type type_list_from_tparams
Definition typelist.hpp:211
test_modifier
Definition typelist.hpp:91
@ invert_test
Keep types when the Filter returns false.
Definition typelist.hpp:93
@ no_invert_test
Keep types when the Filter returns true.
Definition typelist.hpp:92
type_list_sublist< T::size - Count, T::size, T > type_list_suffix
Definition typelist.hpp:277
typename typelist_::apply_each< F, T >::inner_types type_list_apply_each
Definition typelist.hpp:400
typename flatten< T... >::type flatten_t
Converts the template parameters into a type_list.
Definition typelist.hpp:239
type_list_prefix< Count, flatten_t< T... > > flatten_prefix
Definition typelist.hpp:317
type_list_sublist< From, From+Count, T > type_list_sized_sublist
Definition typelist.hpp:259
type_list_remove_suffix< Count, flatten_t< T... > > flatten_remove_suffix
Definition typelist.hpp:341
typename concatenate_type_lists< T... >::type concatenate_type_lists_t
Definition typelist.hpp:173
type_list_apply_each< F, flatten_t< T... > > flatten_apply_each
Definition typelist.hpp:421
type_list_stride< Base, Stride, Count, flatten_t< T... > > flatten_stride
Definition typelist.hpp:507
type_list_suffix< Count, flatten_t< T... > > flatten_suffix
Definition typelist.hpp:323
type_list_sublist< Count, T::size, T > type_list_remove_prefix
Definition typelist.hpp:286
type_list_apply_each_class< F, flatten_t< T... > > flatten_apply_each_class
Definition typelist.hpp:411
typename typelist_::get_type_list_member< I, T >::type type_list_member
Definition typelist.hpp:195
typename get_type_list_sublist< From, To, T >::type type_list_sublist
Definition typelist.hpp:253