UgMisc 0.2-128
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 <type_traits>
10#include <utility>
11
12
42
43
44
45
46namespace ugmisc {
47
48
54
55
56/* *****************************************************************************
57 *
58 * ugmisc::typelist_ namespace contains implementation details
59 *
60 *
61 * Forward declarations in ugmisc namespace are first.
62 *
63 * Then forward declarations in ugmisc::typelist_ namespace.
64 *
65 * Then template type alias declarations in ugmisc follow.
66 *
67 * Then class template definitions.
68 *
69 *
70 * Using this order allows classes like instances of type_list to have methods
71 * which use the template type aliases. The methods can then be used for
72 * convenience by the user.
73 *
74 * ****************************************************************************/
75
76// Forwards in ugmisc.
78template<class...> struct concatenate_type_lists;
80template<class...> struct flatten;
86template<class T> struct get_as_list;
87template<std::size_t, std::size_t, class> struct get_type_list_sublist;
89template<class> struct is_type_list;
90template<class...> struct type_list;
91template<class> struct unwrap;
92template<class> struct wrapped_list;
93
94// Forwards in ugmisc::typelist_.
96namespace typelist_ {
97template<template<class> class, class> struct apply_each;
98template<template<class> class, class, test_modifier>
99 struct filter_type_list;
100template<std::size_t, class> struct get_type_list_member;
101template<std::ptrdiff_t, std::ptrdiff_t, std::size_t, class>
102 struct type_list_stride;
103} /* typelist_ (ugmisc::typelist_) */
105
106
130template<class...T>
132
133
135template<class T> using get_as_list_t = typename get_as_list<T>::type;
136
137
138template<class T> static constexpr bool is_type_list_v = is_type_list<T>::value;
139
140
141template<class...T> static constexpr bool are_type_lists_v = (... && is_type_list_v<T>);
142
143
144
145
153template<std::size_t I, class T> using type_list_member =
154 typename typelist_::get_type_list_member<I, T>::type;
155
156
157
158
181template<class...T> using flatten_t = typename flatten<T...>::type;
182
183
184
185
194template<std::size_t From, std::size_t To, class T>
195using type_list_sublist = typename get_type_list_sublist<From, To, T>::type;
196
200template<std::size_t From, std::size_t Count, class T>
202
209template<std::size_t Count, class T>
211
218template<std::size_t Count, class T>
219using type_list_suffix = type_list_sublist<T::size - Count, T::size, T>;
220
227template<std::size_t Count, class T>
229
236template<std::size_t Count, class T>
237using type_list_remove_suffix = type_list_sublist<0, T::size-Count, T>;
238
239
246template<std::size_t From, std::size_t To, class...T>
248
252template<std::size_t From, std::size_t Count, class...T>
254
258template<std::size_t Count, class...T>
260
264template<std::size_t Count, class...T>
266
273template<std::size_t Count, class...T>
275
282template<std::size_t Count, class...T>
284
285
286
287
302template<
303 template<class> class Test,
304 class T,
306 >
308 typename typelist_::filter_type_list<Test, T, Mod>::type;
309
310
315template<
316 template<class> class Test,
317 class T,
318 test_modifier Mod = static_cast<test_modifier>(0)
319 >
321
322
323
324
331template< template<class> class F, class T >
332using type_list_apply_each_class = typename typelist_::apply_each<F, T>::class_types;
333
334
341template< template<class> class F, class T >
342using type_list_apply_each = typename typelist_::apply_each<F, T>::inner_types;
343
344
352template< template<class> class F, class...T >
354
355
362template< template<class> class F, class...T >
364
365
369template<
370 template<class> class Test,
371 test_modifier Mod,
372 class...T
373 >
374using flatten_filter = type_list_filter<Test, flatten_t<T...>, Mod>;
375
376
377
378
429template<
430 std::ptrdiff_t Base,
431 std::ptrdiff_t Stride,
432 std::size_t Count,
433 class T
434 >
436 typename typelist_::type_list_stride<Base, Stride, Count, T>::type;
437
438
443template<
444 std::ptrdiff_t Base,
445 std::ptrdiff_t Stride,
446 std::size_t Count,
447 class...T
448 >
449using flatten_stride = type_list_stride<Base, Stride, Count, flatten_t<T...>>;
450
451
452
454namespace typelist_ {
455
456template<std::size_t I, class T> struct get_type_list_member {};
457
458template<std::size_t I, class T1, class...T>
459struct get_type_list_member<I, type_list<T1, T...>> {
460 static_assert( I < sizeof...(T) + 1, "Index out of range" );
461 using type = typename get_type_list_member<I-1, type_list<T...>>::type;
462};
463
464template<class T1, class...T> struct get_type_list_member<0, type_list<T1, T...>> {
465 using type = T1;
466};
467
468
469
470
471template<template <class> class Test, class T, test_modifier Mod>
472struct filter_type_list {
473};
474
475
476template<template<class> class Test, test_modifier Mod>
477struct filter_type_list<Test, type_list<>, Mod> {
478 using type = type_list<>;
479};
480
481
482template<template <class> class Test, class T, test_modifier Mod>
483struct filter_type_list<Test, type_list<T>, Mod> {
484 using type = std::conditional_t<
485 Test<T>::value != (Mod == invert_test),
488 >;
489};
490
491
492template<template<class> class Test, test_modifier Mod, class T1, class T2, class...Ts>
493struct filter_type_list<Test, type_list<T1, T2, Ts...>, Mod> {
494private:
495 using all = type_list<T1, T2, Ts...>;
496 static constexpr std::size_t halfway = all::size / 2;
497 using first_half = type_list_prefix<halfway, all>;
498 using second_half = type_list_remove_prefix<halfway, all>;
499
500public:
501 using type = concatenate_type_lists_t<
504 >;
505};
506
507
508template< template<class> class F, class...T >
509struct apply_each<F, type_list<T...>> {
510 using class_types = type_list<F<T>...>;
511 using inner_types = type_list<typename F<T>::type...>;
512};
513
514
515
516
517/*
518 * Used by type_list_stride specialisations. Instantiating one of these
519 * asserts that the stride array doesn't go out of the bounds of the underlying
520 * array.
521 */
522template<
523 std::ptrdiff_t SignedBase,
524 std::ptrdiff_t Stride,
525 std::size_t Count,
526 class T
527 >
528struct type_list_stride_params {
529
530 static_assert( is_type_list_v< T > );
531
532 static constexpr std::size_t Base =
533 (std::size_t)(SignedBase >= 0 ? SignedBase : T::size + SignedBase);
534
535
536 template<std::size_t new_index, bool check = true>
537 static constexpr std::size_t original_index() {
538 static_assert( (!check) || new_index < Count );
539 const std::ptrdiff_t base = Base;
540 return base + ((std::ptrdiff_t)new_index) * Stride;
541 }
542
543
544 template<std::size_t original_index, bool check = true>
545 static constexpr std::size_t new_index() {
546 /*
547 * original_index Io
548 * new_index In
549 * base B
550 * stride S
551 *
552 * Io = B + In*S
553 * In = (Io - B)/S
554 */
555
556 constexpr std::ptrdiff_t dist = ((std::ptrdiff_t)original_index) - Base;
557 constexpr std::ptrdiff_t new_index_signed = dist/Stride;
558 constexpr std::ptrdiff_t new_index_mod = dist%Stride;
559 constexpr std::size_t new_index = (std::size_t)new_index_signed;
560
561 static_assert(
562 (!check) || (new_index >= T::size),
563 "Index out of underlying array bounds."
564 );
565
566 static_assert(
567 (!check) || (original_index >= Count),
568 "Index out of stride array bounds."
569 );
570
571 static_assert(
572 (!check) || (new_index_mod == 0),
573 "Index not touched by the stride array."
574 );
575
576 return new_index;
577 }
578
579
580 // original_index() returns an unsigned index, so we don't need a lower
581 // bound check here.
582 static_assert(
583 Count == 0 || original_index<Count - 1, false>() < T::size,
584 "type_list_stride out of bounds."
585 );
586};
587
588
589
590
591template<
592 std::ptrdiff_t Base,
593 std::ptrdiff_t Stride,
594 std::size_t Count,
595 class T
596 >
597struct type_list_stride {
598private:
599 using params = type_list_stride_params<Base, Stride, Count, T>;
600
601 template<class S> struct deduce_type;
602
603 template<std::size_t...N> struct deduce_type<std::index_sequence<N...>> {
604 using type = ::ugmisc::type_list<
606 >;
607 };
608
609public:
610 using type = typename deduce_type< std::make_index_sequence<Count> >::type;
611};
612
613
614
615} // ugmisc::typelist_
617
618
619
620
621template<class T> struct is_type_list : public std::false_type {};
622
623template<class...T> struct is_type_list<type_list<T...>> : std::true_type {};
624
625
626
627
628template<> struct concatenate_type_lists<> {
629 using type = type_list<>;
630};
631
632
633template<class...T> struct concatenate_type_lists<type_list<T...>> {
634 using type = type_list<T...>;
635};
636
637
638template<class T1, class T2, class T3, class...Ts> struct concatenate_type_lists<T1, T2, T3, Ts...> {
639 static_assert( are_type_lists_v<T1, T2, T3, Ts...> );
640 using type = typename concatenate_type_lists<
641 typename concatenate_type_lists<T1, T2>::type,
642 typename concatenate_type_lists<T3, Ts...>::type
643 >::type;
644};
645
646
647template<class T, class...Ts>
648struct concatenate_type_lists< T, type_list<Ts...> >
649{
650 static_assert( is_type_list_v<T> );
651 using type = typename T::template append<Ts...>;
652};
653
654
655
656
657/*
658 * TODO: Reimplement sublists as a special case of strides.
659 */
660template<std::size_t From, class...T>
661struct get_type_list_sublist<From, From, type_list<T...>> {
662 static_assert( From <= sizeof...(T) );
663 using type = type_list<>;
664};
665
666template<std::size_t From, class...T>
667struct get_type_list_sublist<From, From+1, type_list<T...>> {
668 static_assert( From < sizeof...(T) );
669 using type =
670 type_list< type_list_member<From, type_list<T...>> >;
671};
672
673template<std::size_t From, std::size_t To, class...T>
674struct get_type_list_sublist<From, To, type_list<T...>> {
675private:
676 static_assert( To >= From, "Invalid range: To must be no less than From." );
677 static_assert( To > From+1, "Logic error. Wrong partial specialisation." );
678
679 using list = type_list<T...>;
680
681 static constexpr std::size_t from1 = From;
682 static constexpr std::size_t to1 = From + (To - From)/2;
683 static constexpr std::size_t from2 = to1;
684 static constexpr std::size_t to2 = To;
685
686 using part1 = typename get_type_list_sublist<from1, to1, list>::type;
687 using part2 = typename get_type_list_sublist<from2, to2, list>::type;
688
689public:
690 using type = concatenate_type_lists_t< part1, part2 >;
691};
692
693
694/*
695 * This is deprecated.
696 * Use get_type_list_sublist instead.
697 */
698template<std::size_t From, std::size_t To, class T>
699struct get_type_list_slice : public get_type_list_sublist<From, To, T> {};
700
701
702
703
713template<class T> struct wrapped_list {
714 static_assert(
715 false,
716 "wrapped_list must wrap a wrapped_list or a type_list"
717 );
718};
719
720
721template<class...T> struct wrapped_list<type_list<T...>> {
722 using type = type_list<T...>;
723};
724
725
726template<class T> struct wrapped_list<wrapped_list<T>> {
727 using type = wrapped_list<T>;
728};
729
730
731
732
733template<class T> struct get_as_list {
734 using type = type_list<T>;
735};
736
737
738template<class...T> struct get_as_list<type_list<T...>> {
739 using type = type_list<T...>;
740};
741
742
743// This has never been used or documented.
744template<class T> struct unwrap {
745 using type = T;
746};
747
748
749template<class T> struct unwrap<wrapped_list<T>> {
750 using type = T;
751};
752
753
754template<class...T> struct flatten {
755 // Every flatten special defs a type_list type. The generic one
756 // concatenates the lists created from each tparam.
758};
759
760
761/*
762 * A single type which is not a type_list or wrapped_list is simply put into a
763 * type_list.
764 */
765template<class T> struct flatten<T> {
766 using type = type_list<T>;
767};
768
769
770/*
771 * A type list needs unwrapping recursively, so we flatten each of the member
772 * types.
773 */
774template<class...T> struct flatten< type_list<T...> > {
775 using type = concatenate_type_lists_t<typename flatten<T>::type...>;
776};
777
778
779/*
780 * A wrapped_list is unwrapped once, then the content put into a list.
781 */
782template<class T> struct flatten< wrapped_list<T> > {
783 using type = type_list<T>; // Note the lack of recursion here.
784};
785
786
787
788
792template<class...T> struct type_list {
794 static constexpr std::size_t size = sizeof...(T);
795
797 template<template<class...> class Templ> using apply_t = Templ<T...>;
798
804 template<template<class...> class Templ> using apply = apply_t<Templ>;
805
810 template<template<class...> class Templ> using call_t =
811 typename Templ<T...>::type;
812
818 template<template<class...> class Templ> using call = call_t<Templ>;
819
823 template<class...U>
824 using prepend_t = type_list<U..., T...>;
825
831 template<class...U> using prepend = prepend_t<U...>;
832
836 template<class...U>
837 using append_t = type_list<T..., U...>;
838
844 template<class...U> using append = append_t<U...>;
845
855 template<std::size_t From, std::size_t To>
857
861 template<
862 std::ptrdiff_t Base,
863 std::ptrdiff_t Stride,
864 std::size_t Count
865 >
867
873 template<
874 std::ptrdiff_t Base,
875 std::ptrdiff_t Stride,
876 std::size_t Count
877 >
879};
880
881
882
883
892template<class T, class U>
893constexpr auto operator + (T, U) -> concatenate_type_lists_t<T, U> {
894 return {};
895}
896
897
898} /* ::ugmisc */
899
900#endif /* UGMISC_TYPELIST_HPP */
Definition typelist.hpp:78
Definition typelist.hpp:754
Definition typelist.hpp:733
Definition typelist.hpp:621
Encapsulates a list of types.
Definition typelist.hpp:792
prepend_t< U... > prepend
Definition typelist.hpp:831
type_list< T..., U... > append_t
Definition typelist.hpp:837
type_list_stride< Base, Stride, Count, type_list > stride_t
Definition typelist.hpp:866
append_t< U... > append
Definition typelist.hpp:844
typename Templ< T... >::type call_t
Definition typelist.hpp:810
apply_t< Templ > apply
Definition typelist.hpp:804
type_list_sublist< From, To, type_list > sublist_t
Definition typelist.hpp:856
type_list< U..., T... > prepend_t
Definition typelist.hpp:824
call_t< Templ > call
Definition typelist.hpp:818
static constexpr std::size_t size
Definition typelist.hpp:794
stride_t< Base, Stride, Count > stride
Definition typelist.hpp:878
Templ< T... > apply_t
Definition typelist.hpp:797
Definition typelist.hpp:713
type_list_sized_sublist< From, Count, flatten_t< T... > > flatten_sized_sublist
Definition typelist.hpp:253
type_list_sublist< 0, Count, T > type_list_prefix
Definition typelist.hpp:210
type_list_sublist< From, To, flatten_t< T... > > flatten_sublist
Definition typelist.hpp:247
typename get_as_list< T >::type get_as_list_t
Definition typelist.hpp:135
typename typelist_::type_list_stride< Base, Stride, Count, T >::type type_list_stride
Definition typelist.hpp:435
typename typelist_::apply_each< F, T >::class_types type_list_apply_each_class
Definition typelist.hpp:332
type_list_filter< Test, T, Mod > filter_type_list
Definition typelist.hpp:320
type_list_sublist< 0, T::size-Count, T > type_list_remove_suffix
Definition typelist.hpp:237
type_list_filter< Test, flatten_t< T... >, Mod > flatten_filter
Definition typelist.hpp:374
type_list_remove_prefix< Count, flatten_t< T... > > flatten_remove_prefix
Definition typelist.hpp:274
typename typelist_::filter_type_list< Test, T, Mod >::type type_list_filter
Definition typelist.hpp:307
test_modifier
Definition typelist.hpp:50
@ invert_test
Keep types when the Filter returns false.
Definition typelist.hpp:52
@ no_invert_test
Keep types when the Filter returns true.
Definition typelist.hpp:51
type_list_sublist< T::size - Count, T::size, T > type_list_suffix
Definition typelist.hpp:219
typename typelist_::apply_each< F, T >::inner_types type_list_apply_each
Definition typelist.hpp:342
typename flatten< T... >::type flatten_t
Converts the template parameters into a type_list.
Definition typelist.hpp:181
type_list_prefix< Count, flatten_t< T... > > flatten_prefix
Definition typelist.hpp:259
type_list_sublist< From, From+Count, T > type_list_sized_sublist
Definition typelist.hpp:201
type_list_remove_suffix< Count, flatten_t< T... > > flatten_remove_suffix
Definition typelist.hpp:283
typename concatenate_type_lists< T... >::type concatenate_type_lists_t
Definition typelist.hpp:131
type_list_apply_each< F, flatten_t< T... > > flatten_apply_each
Definition typelist.hpp:363
type_list_stride< Base, Stride, Count, flatten_t< T... > > flatten_stride
Definition typelist.hpp:449
type_list_suffix< Count, flatten_t< T... > > flatten_suffix
Definition typelist.hpp:265
type_list_sublist< Count, T::size, T > type_list_remove_prefix
Definition typelist.hpp:228
type_list_apply_each_class< F, flatten_t< T... > > flatten_apply_each_class
Definition typelist.hpp:353
typename typelist_::get_type_list_member< I, T >::type type_list_member
Definition typelist.hpp:153
typename get_type_list_sublist< From, To, T >::type type_list_sublist
Definition typelist.hpp:195