aboutsummaryrefslogtreecommitdiffstats
path: root/util/generic/typelist.h
blob: c6840cfbbb826928b7fdd5dbf07fb36ecc2ca2d8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#pragma once

#include <util/system/types.h>

#include <util/generic/typetraits.h>

#include <type_traits>

template <class... R>
struct TTypeList;

namespace NTL {
    template <unsigned N, typename TL>
    struct TGetImpl {
        using type = typename TGetImpl<N - 1, typename TL::TTail>::type;
    };

    template <typename TL>
    struct TGetImpl<0u, TL> {
        using type = typename TL::THead;
    };
} // namespace NTL

template <>
struct TTypeList<> {
    static constexpr size_t Length = 0;

    template <class>
    using THave = std::false_type;

    template <template <class> class P>
    struct TSelectBy {
        using type = TTypeList<>;
    };
};

using TNone = TTypeList<>;

template <class H, class... R>
struct TTypeList<H, R...> {
    using THead = H;
    using TTail = TTypeList<R...>;

    static constexpr size_t Length = 1 + sizeof...(R);

    template <class V>
    using THave = TDisjunction<std::is_same<H, V>, typename TTail::template THave<V>>;

    template <unsigned N>
    using TGet = typename ::NTL::TGetImpl<N, TTypeList<H, R...>>::type;

    template <template <class> class P>
    struct TSelectBy {
        using type = std::conditional_t<P<THead>::value, THead, typename TTail::template TSelectBy<P>::type>;
    };
};

// FIXME: temporary to check overall build
template <class T>
struct TTypeList<T, TNone>: public TTypeList<T> {
};

using TCommonSignedInts = TTypeList<signed char, signed short, signed int, signed long, signed long long>;
using TCommonUnsignedInts = TTypeList<unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long, bool>;
using TFixedWidthSignedInts = TTypeList<i8, i16, i32, i64>;
using TFixedWidthUnsignedInts = TTypeList<ui8, ui16, ui32, ui64>;
using TFloats = TTypeList<float, double, long double>;

namespace NTL {
    template <class T1, class T2>
    struct TConcat;

    template <class... R1, class... R2>
    struct TConcat<TTypeList<R1...>, TTypeList<R2...>> {
        using type = TTypeList<R1..., R2...>;
    };

    template <bool isSigned, class T, class TS, class TU>
    struct TTypeSelectorBase {
        using TSignedInts = typename TConcat<TTypeList<T>, TS>::type;
        using TUnsignedInts = TU;
    };

    template <class T, class TS, class TU>
    struct TTypeSelectorBase<false, T, TS, TU> {
        using TSignedInts = TS;
        using TUnsignedInts = typename TConcat<TTypeList<T>, TU>::type;
    };

    template <class T, class TS, class TU>
    struct TTypeSelector: public TTypeSelectorBase<((T)(-1) < 0), T, TS, TU> {
    };

    using T1 = TTypeSelector<char, TCommonSignedInts, TCommonUnsignedInts>;
    using T2 = TTypeSelector<wchar_t, T1::TSignedInts, T1::TUnsignedInts>;
} // namespace NTL

using TSignedInts = NTL::T2::TSignedInts;
using TUnsignedInts = NTL::T2::TUnsignedInts;

template <unsigned sizeOf>
struct TSizeOfPredicate {
    template <class T>
    using TResult = TBoolConstant<sizeof(T) == sizeOf>;
};

template <typename T>
using TFixedWidthSignedInt = typename TFixedWidthSignedInts::template TSelectBy<TSizeOfPredicate<sizeof(T)>::template TResult>::type;

template <typename T>
using TFixedWidthUnsignedInt = typename TFixedWidthUnsignedInts::template TSelectBy<TSizeOfPredicate<sizeof(T)>::template TResult>::type;

template <typename T>
using TFixedWidthFloat = typename TFloats::template TSelectBy<TSizeOfPredicate<sizeof(T)>::template TResult>::type;