summaryrefslogtreecommitdiff
path: root/asl/meta.hpp
blob: 35e238babb068002331380fe6df111400a15c835 (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
174
175
176
177
178
179
180
181
#pragma once

#include "asl/integers.hpp"

namespace asl {

struct empty {};

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

template<typename... Args> static constexpr isize_t types_count = sizeof...(Args);

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 U, typename V> struct _same_as_helper       : false_type {};
template<typename T>             struct _same_as_helper<T, T> : true_type {};

template<typename U, typename V> concept same_as = _same_as_helper<U, V>::value && _same_as_helper<V, U>::value;

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> consteval as_rref_t<T> declval() {}

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

template<typename T> using un_ref_t = _un_ref_t<T>::type;

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

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

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

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

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

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

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

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

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

template<typename T> concept trivially_copyable = __is_trivially_copyable(T);

template<typename T> concept copyable = copy_constructible<T> && copy_assignable<T>;
template<typename T> concept moveable = move_constructible<T> && move_assignable<T>;

template<typename To, typename From>
concept convertible_from = __is_convertible(From, To);

template<typename Derived, class Base>
concept derived_from = __is_class(Derived) && __is_class(Base) && convertible_from<const volatile Base*, const volatile Derived*>;

using nullptr_t = decltype(nullptr);

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

template<typename T> using un_const_t = _un_const_helper<T>::type;

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> struct _un_volatile_helper             { using type = T; };
template<typename T> struct _un_volatile_helper<volatile T> { using type = T; };

template<typename T> using un_volatile_t = _un_volatile_helper<T>::type;

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

template<typename T> using un_cvref_t = un_ref_t<un_cv_t<T>>;

template<typename T> concept is_void = same_as<void, un_cv_t<T>>;

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

template<typename T> concept is_ref = _is_ref_helper<T>::l || _is_ref_helper<T>::r;

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_cv_t<T>>::value;

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

#define TAME_HELPER_IMPL(TRAILING)                                  \
    template<typename R, typename... Args>                          \
    struct _tame_helper<R(Args...) TRAILING> { using type = R(Args...); }

TAME_HELPER_IMPL();
TAME_HELPER_IMPL(&);
TAME_HELPER_IMPL(&&);
TAME_HELPER_IMPL(const);
TAME_HELPER_IMPL(const &);
TAME_HELPER_IMPL(const &&);
TAME_HELPER_IMPL(volatile);
TAME_HELPER_IMPL(volatile &);
TAME_HELPER_IMPL(volatile &&);
TAME_HELPER_IMPL(const volatile);
TAME_HELPER_IMPL(const volatile &);
TAME_HELPER_IMPL(const volatile &&);
TAME_HELPER_IMPL(noexcept);
TAME_HELPER_IMPL(& noexcept);
TAME_HELPER_IMPL(&& noexcept);
TAME_HELPER_IMPL(const noexcept);
TAME_HELPER_IMPL(const & noexcept);
TAME_HELPER_IMPL(const && noexcept);
TAME_HELPER_IMPL(volatile noexcept);
TAME_HELPER_IMPL(volatile & noexcept);
TAME_HELPER_IMPL(volatile && noexcept);
TAME_HELPER_IMPL(const volatile noexcept);
TAME_HELPER_IMPL(const volatile & noexcept);
TAME_HELPER_IMPL(const volatile && noexcept);

#undef TAME_HELPER_IMPL

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

template<typename T>                   struct _is_func_helper             : false_type {};
template<typename R, typename... Args> struct _is_func_helper<R(Args...)> : true_type {};

template<typename T> concept is_func = _is_func_helper<tame_t<T>>::value;

template<typename T> concept is_object = !is_void<T> && !is_ref<T> && !is_func<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> struct _is_floating_point_helper         : false_type {};
template<>           struct _is_floating_point_helper<float>  : true_type  {};
template<>           struct _is_floating_point_helper<double> : true_type  {};

template<typename T> concept is_floating_point = _is_floating_point_helper<un_cv_t<T>>::value;

struct niche {};

template<typename T>
concept has_niche = constructible_from<T, niche> &&
    requires (const T& value, niche n)
    {
        { value == n } -> same_as<bool>;
    };

template<typename T>
concept is_niche = same_as<un_cvref_t<T>, niche>;

} // namespace asl