1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef rr_Traits_hpp
16 #define rr_Traits_hpp
17 
18 #include <stdint.h>
19 #include <type_traits>
20 
21 namespace rr {
22 
23 // Forward declarations
24 class Value;
25 
26 class Void;
27 class Bool;
28 class Byte;
29 class SByte;
30 class Short;
31 class UShort;
32 class Int;
33 class UInt;
34 class Long;
35 class Half;
36 class Float;
37 class Float4;
38 
39 template<class T>
40 class Pointer;
41 template<class T>
42 class LValue;
43 template<class T>
44 class RValue;
45 
46 // IsDefined<T>::value is true if T is a valid type, otherwise false.
47 template<typename T, typename Enable = void>
48 struct IsDefined
49 {
50 	static constexpr bool value = false;
51 };
52 
53 template<typename T>
54 struct IsDefined<T, std::enable_if_t<(sizeof(T) > 0)>>
55 {
56 	static constexpr bool value = true;
57 };
58 
59 template<>
60 struct IsDefined<void>
61 {
62 	static constexpr bool value = true;
63 };
64 
65 // CToReactorT<T> resolves to the corresponding Reactor type for the given C
66 // template type T.
67 template<typename T, typename ENABLE = void>
68 struct CToReactor;
69 template<typename T>
70 using CToReactorT = typename CToReactor<T>::type;
71 
72 // CToReactor specializations for POD types.
73 template<>
74 struct CToReactor<void>
75 {
76 	using type = Void;
77 };
78 template<>
79 struct CToReactor<bool>
80 {
81 	using type = Bool;
82 	static Bool cast(bool);
83 };
84 template<>
85 struct CToReactor<uint8_t>
86 {
87 	using type = Byte;
88 	static Byte cast(uint8_t);
89 };
90 template<>
91 struct CToReactor<int8_t>
92 {
93 	using type = SByte;
94 	static SByte cast(int8_t);
95 };
96 template<>
97 struct CToReactor<int16_t>
98 {
99 	using type = Short;
100 	static Short cast(int16_t);
101 };
102 template<>
103 struct CToReactor<uint16_t>
104 {
105 	using type = UShort;
106 	static UShort cast(uint16_t);
107 };
108 template<>
109 struct CToReactor<int32_t>
110 {
111 	using type = Int;
112 	static Int cast(int32_t);
113 };
114 template<>
115 struct CToReactor<uint32_t>
116 {
117 	using type = UInt;
118 	static UInt cast(uint32_t);
119 };
120 template<>
121 struct CToReactor<float>
122 {
123 	using type = Float;
124 	static Float cast(float);
125 };
126 template<>
127 struct CToReactor<float[4]>
128 {
129 	using type = Float4;
130 	static Float4 cast(float[4]);
131 };
132 
133 // TODO: Long has no constructor that takes a uint64_t
134 template<>
135 struct CToReactor<uint64_t>
136 {
137 	using type = Long; /* static Long   cast(uint64_t); */
138 };
139 
140 // HasReactorType<T>::value resolves to true iff there exists a
141 // CToReactorT specialization for type T.
142 template<typename T>
143 using HasReactorType = IsDefined<CToReactorT<T>>;
144 
145 // CToReactorPtr<T>::type resolves to the corresponding Reactor Pointer<>
146 // type for T*.
147 // For T types that have a CToReactorT<> specialization,
148 // CToReactorPtr<T>::type resolves to Pointer< CToReactorT<T> >, otherwise
149 // CToReactorPtr<T>::type resolves to Pointer<Byte>.
150 template<typename T, typename ENABLE = void>
151 struct CToReactorPtr
152 {
153 	using type = Pointer<Byte>;
154 	static inline type cast(const T *v);  // implemented in Traits.inl
155 };
156 
157 // CToReactorPtr specialization for T types that have a CToReactorT<>
158 // specialization.
159 template<typename T>
160 struct CToReactorPtr<T, std::enable_if_t<HasReactorType<T>::value>>
161 {
162 	using type = Pointer<CToReactorT<T>>;
163 	static inline type cast(const T *v);  // implemented in Traits.inl
164 };
165 
166 // CToReactorPtr specialization for void*.
167 // Maps to Pointer<Byte> instead of Pointer<Void>.
168 template<>
169 struct CToReactorPtr<void, void>
170 {
171 	using type = Pointer<Byte>;
172 	static inline type cast(const void *v);  // implemented in Traits.inl
173 };
174 
175 // CToReactorPtr specialization for function pointer types.
176 // Maps to Pointer<Byte>.
177 // Drops the 'const' qualifier from the cast() method to avoid warnings
178 // about const having no meaning for function types.
179 template<typename T>
180 struct CToReactorPtr<T, std::enable_if_t<std::is_function<T>::value>>
181 {
182 	using type = Pointer<Byte>;
183 	static inline type cast(T *v);  // implemented in Traits.inl
184 };
185 
186 template<typename T>
187 using CToReactorPtrT = typename CToReactorPtr<T>::type;
188 
189 // CToReactor specialization for pointer types.
190 // For T types that have a CToReactorT<> specialization,
191 // CToReactorT<T*>::type resolves to Pointer< CToReactorT<T> >, otherwise
192 // CToReactorT<T*>::type resolves to Pointer<Byte>.
193 template<typename T>
194 struct CToReactor<T, std::enable_if_t<std::is_pointer<T>::value>>
195 {
196 	using elem = typename std::remove_pointer<T>::type;
197 	using type = CToReactorPtrT<elem>;
198 	static inline type cast(T v);  // implemented in Traits.inl
199 };
200 
201 // CToReactor specialization for enum types.
202 template<typename T>
203 struct CToReactor<T, std::enable_if_t<std::is_enum<T>::value>>
204 {
205 	using underlying = typename std::underlying_type<T>::type;
206 	using type = CToReactorT<underlying>;
207 	static type cast(T v);  // implemented in Traits.inl
208 };
209 
210 // IsRValue::value is true if T is of type RValue<X>, where X is any type.
211 template<typename T, typename Enable = void>
212 struct IsRValue
213 {
214 	static constexpr bool value = false;
215 };
216 template<typename T>
217 struct IsRValue<T, std::enable_if_t<IsDefined<typename T::rvalue_underlying_type>::value>>
218 {
219 	static constexpr bool value = true;
220 };
221 
222 // IsLValue::value is true if T is of, or derives from type LValue<T>.
223 template<typename T>
224 struct IsLValue
225 {
226 	static constexpr bool value = std::is_base_of<LValue<T>, T>::value;
227 };
228 
229 // IsReference::value is true if T is of type Reference<X>, where X is any type.
230 template<typename T, typename Enable = void>
231 struct IsReference
232 {
233 	static constexpr bool value = false;
234 };
235 template<typename T>
236 struct IsReference<T, std::enable_if_t<IsDefined<typename T::reference_underlying_type>::value>>
237 {
238 	static constexpr bool value = true;
239 };
240 
241 // ReactorTypeT<T> returns the LValue Reactor type for T.
242 // T can be a C-type, RValue or LValue.
243 template<typename T, typename ENABLE = void>
244 struct ReactorType;
245 template<typename T>
246 using ReactorTypeT = typename ReactorType<T>::type;
247 template<typename T>
248 struct ReactorType<T, std::enable_if_t<IsDefined<CToReactorT<T>>::value>>
249 {
250 	using type = CToReactorT<T>;
castrr::ReactorType251 	static type cast(T v) { return CToReactor<T>::cast(v); }
252 };
253 template<typename T>
254 struct ReactorType<T, std::enable_if_t<IsRValue<T>::value>>
255 {
256 	using type = typename T::rvalue_underlying_type;
castrr::ReactorType257 	static type cast(T v) { return type(v); }
258 };
259 template<typename T>
260 struct ReactorType<T, std::enable_if_t<IsLValue<T>::value>>
261 {
262 	using type = T;
castrr::ReactorType263 	static type cast(T v) { return type(v); }
264 };
265 template<typename T>
266 struct ReactorType<T, std::enable_if_t<IsReference<T>::value>>
267 {
268 	using type = T;
castrr::ReactorType269 	static type cast(T v) { return type(v); }
270 };
271 
272 // Reactor types that can be used as a return type for a function.
273 template<typename T>
274 struct CanBeUsedAsReturn
275 {
276 	static constexpr bool value = false;
277 };
278 template<>
279 struct CanBeUsedAsReturn<Void>
280 {
281 	static constexpr bool value = true;
282 };
283 template<>
284 struct CanBeUsedAsReturn<Int>
285 {
286 	static constexpr bool value = true;
287 };
288 template<>
289 struct CanBeUsedAsReturn<UInt>
290 {
291 	static constexpr bool value = true;
292 };
293 template<>
294 struct CanBeUsedAsReturn<Float>
295 {
296 	static constexpr bool value = true;
297 };
298 template<typename T>
299 struct CanBeUsedAsReturn<Pointer<T>>
300 {
301 	static constexpr bool value = true;
302 };
303 
304 // Reactor types that can be used as a parameter types for a function.
305 template<typename T>
306 struct CanBeUsedAsParameter
307 {
308 	static constexpr bool value = false;
309 };
310 template<>
311 struct CanBeUsedAsParameter<Int>
312 {
313 	static constexpr bool value = true;
314 };
315 template<>
316 struct CanBeUsedAsParameter<UInt>
317 {
318 	static constexpr bool value = true;
319 };
320 template<>
321 struct CanBeUsedAsParameter<Float>
322 {
323 	static constexpr bool value = true;
324 };
325 template<typename T>
326 struct CanBeUsedAsParameter<Pointer<T>>
327 {
328 	static constexpr bool value = true;
329 };
330 
331 // AssertParameterTypeIsValid statically asserts that all template parameter
332 // types can be used as a Reactor function parameter.
333 template<typename T, typename... other>
334 struct AssertParameterTypeIsValid : AssertParameterTypeIsValid<other...>
335 {
336 	static_assert(CanBeUsedAsParameter<T>::value, "Invalid parameter type");
337 };
338 template<typename T>
339 struct AssertParameterTypeIsValid<T>
340 {
341 	static_assert(CanBeUsedAsParameter<T>::value, "Invalid parameter type");
342 };
343 
344 // AssertFunctionSignatureIsValid statically asserts that the Reactor
345 // function signature is valid.
346 template<typename Return, typename... Arguments>
347 class AssertFunctionSignatureIsValid;
348 template<typename Return>
349 class AssertFunctionSignatureIsValid<Return(Void)>
350 {};
351 template<typename Return, typename... Arguments>
352 class AssertFunctionSignatureIsValid<Return(Arguments...)>
353 {
354 	static_assert(CanBeUsedAsReturn<Return>::value, "Invalid return type");
355 	static_assert(sizeof(AssertParameterTypeIsValid<Arguments...>) >= 0, "");
356 };
357 
358 }  // namespace rr
359 
360 #endif  // rr_Traits_hpp
361