ugmisc 0.2-76
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#pragma once
25
26#include <cstddef>
27#include <type_traits>
28#include <utility>
29
30
60
61
62
63
64namespace ugmisc {
65
66
72
73
74/* *****************************************************************************
75 *
76 * ugmisc::typelist_ namespace contains implementation details
77 *
78 *
79 * Forward declarations in ugmisc namespace are first.
80 *
81 * Then forward declarations in ugmisc::typelist_ namespace.
82 *
83 * Then template type alias declarations in ugmisc follow.
84 *
85 * Then class template definitions.
86 *
87 *
88 * Using this order allows classes like instances of type_list to have methods
89 * which use the template type aliases. The methods can then be used for
90 * convenience by the user.
91 *
92 * ****************************************************************************/
93
94// Forwards in ugmisc.
96template<class...> struct concatenate_type_lists;
98template<class...> struct flatten;
104template<class T> struct get_as_list;
105template<std::size_t, std::size_t, class> struct get_type_list_sublist;
107template<class> struct is_type_list;
108template<class...> struct type_list;
109template<class> struct unwrap;
110template<class> struct wrapped_list;
111
112// Forwards in ugmisc::typelist_.
114namespace typelist_ {
115template<template<class> class, class> struct apply_each;
116template<template<class> class, class, test_modifier>
117 struct filter_type_list;
118template<std::size_t, class> struct get_type_list_member;
119template<std::ptrdiff_t, std::ptrdiff_t, std::size_t, class>
120 struct type_list_stride;
121} /* typelist_ (ugmisc::typelist_) */
123
124
148template<class...T>
150
151
153template<class T> using get_as_list_t = typename get_as_list<T>::type;
154
155
156template<class T> static constexpr bool is_type_list_v = is_type_list<T>::value;
157
158
159template<class...T> static constexpr bool are_type_lists_v = (... && is_type_list_v<T>);
160
161
162
163
171template<std::size_t I, class T> using type_list_member =
172 typename typelist_::get_type_list_member<I, T>::type;
173
174
175
176
199template<class...T> using flatten_t = typename flatten<T...>::type;
200
201
202
203
212template<std::size_t From, std::size_t To, class T>
213using type_list_sublist = typename get_type_list_sublist<From, To, T>::type;
214
218template<std::size_t From, std::size_t Count, class T>
220
227template<std::size_t Count, class T>
229
236template<std::size_t Count, class T>
237using type_list_suffix = type_list_sublist<T::size - Count, T::size, T>;
238
245template<std::size_t Count, class T>
247
254template<std::size_t Count, class T>
255using type_list_remove_suffix = type_list_sublist<0, T::size-Count, T>;
256
257
264template<std::size_t From, std::size_t To, class...T>
266
270template<std::size_t From, std::size_t Count, class...T>
272
276template<std::size_t Count, class...T>
278
282template<std::size_t Count, class...T>
284
291template<std::size_t Count, class...T>
293
300template<std::size_t Count, class...T>
302
303
304
305
320template<
321 template<class> class Test,
322 class T,
324 >
326 typename typelist_::filter_type_list<Test, T, Mod>::type;
327
328
333template<
334 template<class> class Test,
335 class T,
336 test_modifier Mod = static_cast<test_modifier>(0)
337 >
339
340
341
342
349template< template<class> class F, class T >
350using type_list_apply_each_class = typename typelist_::apply_each<F, T>::class_types;
351
352
359template< template<class> class F, class T >
360using type_list_apply_each = typename typelist_::apply_each<F, T>::inner_types;
361
362
370template< template<class> class F, class...T >
372
373
380template< template<class> class F, class...T >
382
383
387template<
388 template<class> class Test,
389 test_modifier Mod,
390 class...T
391 >
392using flatten_filter = type_list_filter<Test, flatten_t<T...>, Mod>;
393
394
395
396
447template<
448 std::ptrdiff_t Base,
449 std::ptrdiff_t Stride,
450 std::size_t Count,
451 class T
452 >
454 typename typelist_::type_list_stride<Base, Stride, Count, T>::type;
455
456
461template<
462 std::ptrdiff_t Base,
463 std::ptrdiff_t Stride,
464 std::size_t Count,
465 class...T
466 >
467using flatten_stride = type_list_stride<Base, Stride, Count, flatten_t<T...>>;
468
469
470
472namespace typelist_ {
473
474template<std::size_t I, class T> struct get_type_list_member {};
475
476template<std::size_t I, class T1, class...T>
477struct get_type_list_member<I, type_list<T1, T...>> {
478 static_assert( I < sizeof...(T) + 1, "Index out of range" );
479 using type = typename get_type_list_member<I-1, type_list<T...>>::type;
480};
481
482template<class T1, class...T> struct get_type_list_member<0, type_list<T1, T...>> {
483 using type = T1;
484};
485
486
487
488
489template<template <class> class Test, class T, test_modifier Mod>
490struct filter_type_list {
491};
492
493
494template<template<class> class Test, test_modifier Mod>
495struct filter_type_list<Test, type_list<>, Mod> {
496 using type = type_list<>;
497};
498
499
500template<template <class> class Test, class T, test_modifier Mod>
501struct filter_type_list<Test, type_list<T>, Mod> {
502 using type = std::conditional_t<
503 Test<T>::value != (Mod == invert_test),
506 >;
507};
508
509
510template<template<class> class Test, test_modifier Mod, class T1, class T2, class...Ts>
511struct filter_type_list<Test, type_list<T1, T2, Ts...>, Mod> {
512private:
513 using all = type_list<T1, T2, Ts...>;
514 static constexpr std::size_t halfway = all::size / 2;
515 using first_half = type_list_prefix<halfway, all>;
516 using second_half = type_list_remove_prefix<halfway, all>;
517
518public:
519 using type = concatenate_type_lists_t<
522 >;
523};
524
525
526template< template<class> class F, class...T >
527struct apply_each<F, type_list<T...>> {
528 using class_types = type_list<F<T>...>;
529 using inner_types = type_list<typename F<T>::type...>;
530};
531
532
533
534
535/*
536 * Used by type_list_stride specialisations. Instantiating one of these
537 * asserts that the stride array doesn't go out of the bounds of the underlying
538 * array.
539 */
540template<
541 std::ptrdiff_t SignedBase,
542 std::ptrdiff_t Stride,
543 std::size_t Count,
544 class T
545 >
546struct type_list_stride_params {
547
548 static_assert( is_type_list_v< T > );
549
550 static constexpr std::size_t Base =
551 (std::size_t)(SignedBase >= 0 ? SignedBase : T::size + SignedBase);
552
553
554 template<std::size_t new_index, bool check = true>
555 static constexpr std::size_t original_index() {
556 static_assert( (!check) || new_index < Count );
557 const std::ptrdiff_t base = Base;
558 return base + ((std::ptrdiff_t)new_index) * Stride;
559 }
560
561
562 template<std::size_t original_index, bool check = true>
563 static constexpr std::size_t new_index() {
564 /*
565 * original_index Io
566 * new_index In
567 * base B
568 * stride S
569 *
570 * Io = B + In*S
571 * In = (Io - B)/S
572 */
573
574 constexpr std::ptrdiff_t dist = ((std::ptrdiff_t)original_index) - Base;
575 constexpr std::ptrdiff_t new_index_signed = dist/Stride;
576 constexpr std::ptrdiff_t new_index_mod = dist%Stride;
577 constexpr std::size_t new_index = (std::size_t)new_index_signed;
578
579 static_assert(
580 (!check) || (new_index >= T::size),
581 "Index out of underlying array bounds."
582 );
583
584 static_assert(
585 (!check) || (original_index >= Count),
586 "Index out of stride array bounds."
587 );
588
589 static_assert(
590 (!check) || (new_index_mod == 0),
591 "Index not touched by the stride array."
592 );
593
594 return new_index;
595 }
596
597
598 // original_index() returns an unsigned index, so we don't need a lower
599 // bound check here.
600 static_assert(
601 Count == 0 || original_index<Count - 1, false>() < T::size,
602 "type_list_stride out of bounds."
603 );
604};
605
606
607
608
609template<
610 std::ptrdiff_t Base,
611 std::ptrdiff_t Stride,
612 std::size_t Count,
613 class T
614 >
615struct type_list_stride {
616private:
617 using params = type_list_stride_params<Base, Stride, Count, T>;
618
619 template<class S> struct deduce_type;
620
621 template<std::size_t...N> struct deduce_type<std::index_sequence<N...>> {
622 using type = ::ugmisc::type_list<
624 >;
625 };
626
627public:
628 using type = typename deduce_type< std::make_index_sequence<Count> >::type;
629};
630
631
632
633} // ugmisc::typelist_
635
636
637
638
639template<class T> struct is_type_list : public std::false_type {};
640
641template<class...T> struct is_type_list<type_list<T...>> : std::true_type {};
642
643
644
645
646template<> struct concatenate_type_lists<> {
647 using type = type_list<>;
648};
649
650
651template<class...T> struct concatenate_type_lists<type_list<T...>> {
652 using type = type_list<T...>;
653};
654
655
656template<class T1, class T2, class T3, class...Ts> struct concatenate_type_lists<T1, T2, T3, Ts...> {
657 static_assert( are_type_lists_v<T1, T2, T3, Ts...> );
658 using type = typename concatenate_type_lists<
659 typename concatenate_type_lists<T1, T2>::type,
660 typename concatenate_type_lists<T3, Ts...>::type
661 >::type;
662};
663
664
665template<class T, class...Ts>
666struct concatenate_type_lists< T, type_list<Ts...> >
667{
668 static_assert( is_type_list_v<T> );
669 using type = typename T::template append<Ts...>;
670};
671
672
673
674
675/*
676 * TODO: Reimplement sublists as a special case of strides.
677 */
678template<std::size_t From, class...T>
679struct get_type_list_sublist<From, From, type_list<T...>> {
680 static_assert( From <= sizeof...(T) );
681 using type = type_list<>;
682};
683
684template<std::size_t From, class...T>
685struct get_type_list_sublist<From, From+1, type_list<T...>> {
686 static_assert( From < sizeof...(T) );
687 using type =
688 type_list< type_list_member<From, type_list<T...>> >;
689};
690
691template<std::size_t From, std::size_t To, class...T>
692struct get_type_list_sublist<From, To, type_list<T...>> {
693private:
694 static_assert( To >= From, "Invalid range: To must be no less than From." );
695 static_assert( To > From+1, "Logic error. Wrong partial specialisation." );
696
697 using list = type_list<T...>;
698
699 static constexpr std::size_t from1 = From;
700 static constexpr std::size_t to1 = From + (To - From)/2;
701 static constexpr std::size_t from2 = to1;
702 static constexpr std::size_t to2 = To;
703
704 using part1 = typename get_type_list_sublist<from1, to1, list>::type;
705 using part2 = typename get_type_list_sublist<from2, to2, list>::type;
706
707public:
708 using type = concatenate_type_lists_t< part1, part2 >;
709};
710
711
712/*
713 * This is deprecated.
714 * Use get_type_list_sublist instead.
715 */
716template<std::size_t From, std::size_t To, class T>
717struct get_type_list_slice : public get_type_list_sublist<From, To, T> {};
718
719
720
721
731template<class T> struct wrapped_list {
732 static_assert(
733 false,
734 "wrapped_list must wrap a wrapped_list or a type_list"
735 );
736};
737
738
739template<class...T> struct wrapped_list<type_list<T...>> {
740 using type = type_list<T...>;
741};
742
743
744template<class T> struct wrapped_list<wrapped_list<T>> {
745 using type = wrapped_list<T>;
746};
747
748
749
750
751template<class T> struct get_as_list {
752 using type = type_list<T>;
753};
754
755
756template<class...T> struct get_as_list<type_list<T...>> {
757 using type = type_list<T...>;
758};
759
760
761// This has never been used or documented.
762template<class T> struct unwrap {
763 using type = T;
764};
765
766
767template<class T> struct unwrap<wrapped_list<T>> {
768 using type = T;
769};
770
771
772template<class...T> struct flatten {
773 // Every flatten special defs a type_list type. The generic one
774 // concatenates the lists created from each tparam.
776};
777
778
779/*
780 * A single type which is not a type_list or wrapped_list is simply put into a
781 * type_list.
782 */
783template<class T> struct flatten<T> {
784 using type = type_list<T>;
785};
786
787
788/*
789 * A type list needs unwrapping recursively, so we flatten each of the member
790 * types.
791 */
792template<class...T> struct flatten< type_list<T...> > {
793 using type = concatenate_type_lists_t<typename flatten<T>::type...>;
794};
795
796
797/*
798 * A wrapped_list is unwrapped once, then the content put into a list.
799 */
800template<class T> struct flatten< wrapped_list<T> > {
801 using type = type_list<T>; // Note the lack of recursion here.
802};
803
804
805
806
810template<class...T> struct type_list {
812 static constexpr std::size_t size = sizeof...(T);
813
815 template<template<class...> class Templ> using apply_t = Templ<T...>;
816
822 template<template<class...> class Templ> using apply = apply_t<Templ>;
823
828 template<template<class...> class Templ> using call_t =
829 typename Templ<T...>::type;
830
836 template<template<class...> class Templ> using call = call_t<Templ>;
837
841 template<class...U>
842 using prepend_t = type_list<U..., T...>;
843
849 template<class...U> using prepend = prepend_t<U...>;
850
854 template<class...U>
855 using append_t = type_list<T..., U...>;
856
862 template<class...U> using append = append_t<U...>;
863
873 template<std::size_t From, std::size_t To>
875
879 template<
880 std::ptrdiff_t Base,
881 std::ptrdiff_t Stride,
882 std::size_t Count
883 >
885
891 template<
892 std::ptrdiff_t Base,
893 std::ptrdiff_t Stride,
894 std::size_t Count
895 >
897};
898
899
900
901
910template<class T, class U>
911constexpr auto operator + (T, U) -> concatenate_type_lists_t<T, U> {
912 return {};
913}
914
915
916} /* ::ugmisc */
Definition typelist.hpp:96
Definition typelist.hpp:772
Definition typelist.hpp:751
Definition typelist.hpp:639
Encapsulates a list of types.
Definition typelist.hpp:810
prepend_t< U... > prepend
Definition typelist.hpp:849
type_list< T..., U... > append_t
Definition typelist.hpp:855
type_list_stride< Base, Stride, Count, type_list > stride_t
Definition typelist.hpp:884
append_t< U... > append
Definition typelist.hpp:862
typename Templ< T... >::type call_t
Definition typelist.hpp:828
apply_t< Templ > apply
Definition typelist.hpp:822
type_list_sublist< From, To, type_list > sublist_t
Definition typelist.hpp:874
type_list< U..., T... > prepend_t
Definition typelist.hpp:842
call_t< Templ > call
Definition typelist.hpp:836
static constexpr std::size_t size
Definition typelist.hpp:812
stride_t< Base, Stride, Count > stride
Definition typelist.hpp:896
Templ< T... > apply_t
Definition typelist.hpp:815
Definition typelist.hpp:731
type_list_sized_sublist< From, Count, flatten_t< T... > > flatten_sized_sublist
Definition typelist.hpp:271
type_list_sublist< 0, Count, T > type_list_prefix
Definition typelist.hpp:228
type_list_sublist< From, To, flatten_t< T... > > flatten_sublist
Definition typelist.hpp:265
typename get_as_list< T >::type get_as_list_t
Definition typelist.hpp:153
typename typelist_::apply_each< F, T >::class_types type_list_apply_each_class
Definition typelist.hpp:350
type_list_filter< Test, T, Mod > filter_type_list
Definition typelist.hpp:338
type_list_sublist< 0, T::size-Count, T > type_list_remove_suffix
Definition typelist.hpp:255
type_list_filter< Test, flatten_t< T... >, Mod > flatten_filter
Definition typelist.hpp:392
type_list_remove_prefix< Count, flatten_t< T... > > flatten_remove_prefix
Definition typelist.hpp:292
test_modifier
Definition typelist.hpp:68
@ invert_test
Keep types when the Filter returns false.
Definition typelist.hpp:70
@ no_invert_test
Keep types when the Filter returns true.
Definition typelist.hpp:69
type_list_sublist< T::size - Count, T::size, T > type_list_suffix
Definition typelist.hpp:237
typename typelist_::filter_type_list< Test, T, Mod >::type type_list_filter
Definition typelist.hpp:325
typename typelist_::apply_each< F, T >::inner_types type_list_apply_each
Definition typelist.hpp:360
typename flatten< T... >::type flatten_t
Converts the template parameters into a type_list.
Definition typelist.hpp:199
type_list_prefix< Count, flatten_t< T... > > flatten_prefix
Definition typelist.hpp:277
type_list_sublist< From, From+Count, T > type_list_sized_sublist
Definition typelist.hpp:219
typename typelist_::type_list_stride< Base, Stride, Count, T >::type type_list_stride
Definition typelist.hpp:453
type_list_remove_suffix< Count, flatten_t< T... > > flatten_remove_suffix
Definition typelist.hpp:301
typename concatenate_type_lists< T... >::type concatenate_type_lists_t
Definition typelist.hpp:149
type_list_apply_each< F, flatten_t< T... > > flatten_apply_each
Definition typelist.hpp:381
type_list_stride< Base, Stride, Count, flatten_t< T... > > flatten_stride
Definition typelist.hpp:467
type_list_suffix< Count, flatten_t< T... > > flatten_suffix
Definition typelist.hpp:283
typename typelist_::get_type_list_member< I, T >::type type_list_member
Definition typelist.hpp:171
type_list_sublist< Count, T::size, T > type_list_remove_prefix
Definition typelist.hpp:246
type_list_apply_each_class< F, flatten_t< T... > > flatten_apply_each_class
Definition typelist.hpp:371
typename get_type_list_sublist< From, To, T >::type type_list_sublist
Definition typelist.hpp:213