1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef IORAP_COMMON_TYPE_H
18 #define IORAP_COMMON_TYPE_H
19
20 #include <cstdint>
21 #include <tuple>
22
23 namespace iorap {
24 namespace introspect {
25
26 /*
27 * Simple types-as-value abstractions.
28 *
29 * Allow types to be passed as regular function parameters instead of using 'template' type
30 * parameters.
31 *
32 * This enables the following, more concise, pattern:
33 * ----------------------------
34 *
35 * Traditional metaprogramming with template parameters:
36 *
37 * template <typename ... Args>
38 * struct get_num_params {
39 * static constexpr size_t value = sizeof...(Args);
40 * };
41 *
42 * typename get_num_params<decltype("hello"), decltype("world")>::value == 2
43 * typename get_num_params<decltype(int), decltype(int), decltype(int), decltype(int)>::value == 4
44 *
45 * Alternative metaprogramming with values:
46 *
47 * constexpr auto get_num_params = [](auto&&... val) { return sizeof...(val); };
48 *
49 * get_num_params("hello", "world") == 2
50 * get_num_params(0,0,0,0) == 4
51 */
52
53 /*
54 * A fully instantiated type wrapper.
55 *
56 * basic_type<T> is intended for overloading functions between different basic_types.
57 * type_c<T> is intended for instantiating new type wrappers as a short-hand (and not requiring
58 * typename).
59 *
60 * For basic_type<T> in particular it allows one to overload on basic_type<T> to handle specific
61 * types, and there's no requirement that T be constexpr, be default constructible, and no
62 * template specializations is necessary.
63 *
64 * void foo(basic_type<int>) {
65 * printf("int");
66 * }
67 *
68 * template <typename T>
69 * void foo(basic_type<T>) {
70 * printf("everything else");
71 * }
72 *
73 * as opposed to this verbosity
74 *
75 * template <typename T>
76 * struct foo {
77 * void operator() {
78 * printf("everything else");
79 * }
80 * };
81 *
82 * template <>
83 * struct foo<int> {
84 * void operator() {
85 * printf("int");
86 * }
87 * };
88 *
89 * OR this super-hack which works in rare situations
90 *
91 * void foo(int) {
92 * printf("int");
93 * }
94 *
95 * template <typename T>
96 * void foo(T&&) {
97 * printf("everything else")
98 * }
99 *
100 * Note that invoking the last foo(T&&) is particularly challenging. declval<T> fails at compilation
101 * with a static_assert, so a real value has to be constructed that is immediately discarded.
102 */
103 template <typename T>
104 struct basic_type {
105 using type = T;
106 };
107
108 template <typename T>
109 struct type_impl {
110 struct _ : basic_type<T> { };
111 };
112
113 template <typename T>
114 using type = basic_type<T>; // typename type_impl<T>::_; // subclass of basic_type<T>
115 // TODO: why doesn't using type_impl::_ work with ADL?
116
117 template <typename T>
118 using type_t = type<T>;
119
120 template <typename T>
121 constexpr auto type_c = type<T>{};
122
123 template <auto X>
124 struct value_constant {
125 static constexpr auto value = X;
126 };
127
128 template <int X>
129 constexpr auto int_c = value_constant<X>{};
130
131 template <typename T>
132 constexpr bool dependent_false_v = false;
133
134 // Emit a static_assert(false) if the else branch in an 'if constexpr' is taken.
135 // Needs a type as the first parameter.
136 #define STATIC_FAIL(T, msg) static_assert(::iorap::introspect::dependent_false_v<T>, msg)
137 // Emit a static_assert(false) if an else branch in an 'if constexpr' is taken, used with
138 // (e.g. auto) values instead of types.
139 #define STATIC_FAIL_DT(var, msg) STATIC_FAIL(decltype(var), msg)
140
141 template <size_t i, typename Tuple, typename F>
for_each_impl(Tuple && t,F && f)142 static constexpr void for_each_impl(Tuple&& t, F&& f) {
143 if constexpr (i == std::tuple_size<std::decay_t<Tuple>>::value) {
144 return;
145 } else {
146 f(std::get<i>(std::forward<Tuple>(t)));
147 for_each_impl<i+1>(std::forward<Tuple>(t), std::forward<F>(f));
148 }
149 }
150
151 // for each Tuple<a1,a2,...,aN> invoke { f(a1); f(a2); ... ; f(aN); }
152 template <typename Tuple, typename F>
for_each(Tuple && t,F && f)153 static constexpr void for_each(Tuple&& t, F&& f) {
154 return for_each_impl<0u>(std::forward<Tuple>(t), std::forward<F>(f));
155 }
156
157 // Perfect forwarding for structured binding.
158 //
159 // Example:
160 // auto&& [a,b] = whatever;
161 // return aliasing_forward<T>(a);
162 template <typename T, typename U>
decltype(auto)163 constexpr decltype(auto) aliasing_forward(U&& val) noexcept {
164 if constexpr (std::is_lvalue_reference_v<T>) {
165 return val;
166 } else {
167 return std::move(val);
168 }
169 }
170
171
172 } // namespace introspect
173 } // namespace iorap
174
175 #endif // IORAP_COMMON_TYPE_H
176