summaryrefslogtreecommitdiff
path: root/asl/meta.hpp
blob: 4a5b4488b2cbe68578dd1cba7cfc6adc47757b18 (plain)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#pragma once

namespace asl {

template<typename T> struct id { using type = T; };

template<typename T, T kValue> struct integral_constant { static constexpr T value = kValue; };
template<bool B> using bool_constant = integral_constant<bool, B>;

using true_type  = bool_constant<true>;
using false_type = bool_constant<false>;

template<bool kSelect, typename U, typename V> struct _select_helper             { using type = V; };
template<typename U, typename V>               struct _select_helper<true, U, V> { using type = U; };

template<bool kSelect, typename U, typename V> using select_t = _select_helper<kSelect, U, V>::type;

template<typename T> auto _as_lref_helper(int) -> id<T&>;
template<typename T> auto _as_lref_helper(...) -> id<T>;

template<typename T> auto _as_rref_helper(int) -> id<T&&>;
template<typename T> auto _as_rref_helper(...) -> id<T>;

template<typename T> using as_lref_t = decltype(_as_lref_helper<T>(0))::type;
template<typename T> using as_rref_t = decltype(_as_rref_helper<T>(0))::type;

template<typename T, typename... Args> concept constructible = __is_constructible(T, Args...);

template<typename T> concept default_constructible = constructible<T>;
template<typename T> concept copy_constructible    = constructible<T, as_lref_t<const T>>;
template<typename T> concept move_constructible    = constructible<T, as_rref_t<T>>;

template<typename T, typename... Args> concept trivially_constructible = __is_trivially_constructible(T, Args...);

template<typename T> concept trivially_default_constructible = trivially_constructible<T>;
template<typename T> concept trivially_copy_constructible    = trivially_constructible<T, as_lref_t<const T>>;
template<typename T> concept trivially_move_constructible    = trivially_constructible<T, as_rref_t<T>>;

template<typename T, typename... Args> concept assignable = __is_assignable(T, Args...);

template<typename T> concept copy_assignable = assignable<as_lref_t<T>, as_lref_t<const T>>;
template<typename T> concept move_assignable = assignable<as_lref_t<T>, as_rref_t<T>>;

template<typename T, typename... Args> concept trivially_assignable = __is_trivially_assignable(T, Args...);

template<typename T> concept trivially_copy_assignable = trivially_assignable<as_lref_t<T>, as_lref_t<const T>>;
template<typename T> concept trivially_move_assignable = trivially_assignable<as_lref_t<T>, as_rref_t<T>>;

template<typename T> concept trivially_destructible = __is_trivially_destructible(T);

using nullptr_t = decltype(nullptr);

template<typename T> struct un_ref      { using type = T; };
template<typename T> struct un_ref<T&>  { using type = T; };
template<typename T> struct un_ref<T&&> { using type = T; };
template<typename T> using  un_ref_t = un_ref<T>::type;

template<typename T> struct un_const          { using type = T; };
template<typename T> struct un_const<const T> { using type = T; };
template<typename T> using  un_const_t = un_const<T>::type;

template<typename T> struct un_volatile             { using type = T; };
template<typename T> struct un_volatile<volatile T> { using type = T; };
template<typename T> using  un_volatile_t = un_volatile<T>::type;

template<typename T> using un_qual_t = un_const_t<un_volatile_t<T>>;

template<typename T> using un_qualref_t = un_qual_t<un_ref_t<T>>;

template<typename U, typename V> struct _is_same_helper       : false_type {};
template<typename T>             struct _is_same_helper<T, T> : true_type  {};

template<typename U, typename V>
concept is_same = _is_same_helper<U, V>::value && _is_same_helper<V, U>::value;

template<typename T> struct _is_const_helper          : false_type {};
template<typename T> struct _is_const_helper<const T> : true_type  {};

template<typename T> concept is_const = _is_const_helper<T>::value;

template<typename T> concept is_void    = is_same<un_qual_t<T>, void>;
template<typename T> concept is_nullptr = is_same<un_qual_t<T>, nullptr_t>;

template<typename T> concept is_integral       = __is_integral(T);
template<typename T> concept is_floating_point = __is_floating_point(T);
template<typename T> concept is_arithmetic     = is_integral<T> || is_floating_point<T>;

template<typename T>            struct _is_array_helper       : false_type {};
template<typename T>            struct _is_array_helper<T[]>  : true_type  {};
template<typename T, int N> struct _is_array_helper<T[N]> : true_type  {};

template<typename T> concept is_array = _is_array_helper<T>::value;

template<typename T> concept is_class = __is_class(T);
template<typename T> concept is_union = __is_union(T);

template<typename T> concept is_enum  = __is_enum(T);

template<typename T> struct _is_ptr_helper     : false_type {};
template<typename T> struct _is_ptr_helper<T*> : true_type  {};

template<typename T> concept is_ptr = _is_ptr_helper<un_qual_t<T>>::value;

template<typename T> struct _is_ref_helper      { static constexpr bool lref = false; static constexpr bool rref = false; };
template<typename T> struct _is_ref_helper<T&>  { static constexpr bool lref = true;  static constexpr bool rref = false; };
template<typename T> struct _is_ref_helper<T&&> { static constexpr bool lref = false; static constexpr bool rref = true;  };

template<typename T> concept is_lref = _is_ref_helper<T>::lref;
template<typename T> concept is_rref = _is_ref_helper<T>::rref;
template<typename T> concept is_ref  = is_lref<T> || is_rref<T>;

template<typename T> concept is_func = !is_const<const T> && !is_ref<T>;

template<typename T>             struct _is_member_ptr_helper         : false_type {};
template<typename T, typename U> struct _is_member_ptr_helper<T U::*> : true_type  {};

template<typename T>             struct _is_member_func_ptr_helper         : false_type {};
template<typename T, typename U> struct _is_member_func_ptr_helper<T U::*> : bool_constant<is_func<T>>  {};

template<typename T> concept is_member_ptr        = _is_member_ptr_helper<un_qual_t<T>>::value;
template<typename T> concept is_member_func_ptr   = _is_member_func_ptr_helper<un_qual_t<T>>::value;
template<typename T> concept is_member_object_ptr = is_member_ptr<T> && !is_member_func_ptr<T>;

template<typename T> concept is_fundamental = is_arithmetic<T> || is_void<T> || is_nullptr<T>;
template<typename T> concept is_compound    = !is_fundamental<T>;
template<typename T> concept is_scalar      = (is_fundamental<T> && !is_void<T>) || is_enum<T> || is_ptr<T> || is_member_ptr<T>;
template<typename T> concept is_object      = is_scalar<T> || is_class<T> || is_union<T>;

template<typename T> concept is_empty = is_void<T> || __is_empty(T);

struct empty {};

template<typename T> using devoid_t = select_t<is_void<T>, empty, T>;

template<typename F> struct _tame_helper { using type = F; };

#define ASL_TAME_IMPL(SUFFIX) \
    template<typename Ret, typename... Args> \
    struct _tame_helper<Ret(Args...) SUFFIX> { using type = Ret(Args...); }

ASL_TAME_IMPL();
ASL_TAME_IMPL(const);
ASL_TAME_IMPL(volatile);
ASL_TAME_IMPL(volatile const);
ASL_TAME_IMPL(&&);
ASL_TAME_IMPL(const &&);
ASL_TAME_IMPL(volatile &&);
ASL_TAME_IMPL(volatile const &&);
ASL_TAME_IMPL(&);
ASL_TAME_IMPL(const &);
ASL_TAME_IMPL(volatile &);
ASL_TAME_IMPL(volatile const &);
ASL_TAME_IMPL(noexcept);
ASL_TAME_IMPL(const noexcept);
ASL_TAME_IMPL(volatile noexcept);
ASL_TAME_IMPL(volatile const noexcept);
ASL_TAME_IMPL(&& noexcept);
ASL_TAME_IMPL(const && noexcept);
ASL_TAME_IMPL(volatile && noexcept);
ASL_TAME_IMPL(volatile const && noexcept);
ASL_TAME_IMPL(& noexcept);
ASL_TAME_IMPL(const & noexcept);
ASL_TAME_IMPL(volatile & noexcept);
ASL_TAME_IMPL(volatile const & noexcept);

#undef ASL_TAME_IMPL

template<typename T> using tame_t = _tame_helper<T>::type;

template<typename T> using as_raw_ptr_t = un_ref_t<tame_t<T>>*;


} // namespace asl