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 | #ifdef Bool |
22 | #undef Bool // b/127920555 |
23 | #endif |
24 | |
25 | namespace rr |
26 | { |
27 | // Forward declarations |
28 | class Value; |
29 | |
30 | class Void; |
31 | class Bool; |
32 | class Byte; |
33 | class SByte; |
34 | class Short; |
35 | class UShort; |
36 | class Int; |
37 | class UInt; |
38 | class Long; |
39 | class Half; |
40 | class Float; |
41 | |
42 | template<class T> class Pointer; |
43 | template<class T> class LValue; |
44 | template<class T> 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, typename std::enable_if<(sizeof(T)>0)>::type> |
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> struct CToReactor; |
68 | template<typename T> using CToReactorT = typename CToReactor<T>::type; |
69 | |
70 | // CToReactor specializations for POD types. |
71 | template<> struct CToReactor<void> { using type = Void; }; |
72 | template<> struct CToReactor<bool> { using type = Bool; static Bool cast(bool); }; |
73 | template<> struct CToReactor<uint8_t> { using type = Byte; static Byte cast(uint8_t); }; |
74 | template<> struct CToReactor<int8_t> { using type = SByte; static SByte cast(int8_t); }; |
75 | template<> struct CToReactor<int16_t> { using type = Short; static Short cast(int16_t); }; |
76 | template<> struct CToReactor<uint16_t> { using type = UShort; static UShort cast(uint16_t); }; |
77 | template<> struct CToReactor<int32_t> { using type = Int; static Int cast(int32_t); }; |
78 | template<> struct CToReactor<uint32_t> { using type = UInt; static UInt cast(uint32_t); }; |
79 | template<> struct CToReactor<float> { using type = Float; static Float cast(float); }; |
80 | |
81 | // TODO: Long has no constructor that takes a uint64_t |
82 | template<> struct CToReactor<uint64_t> { using type = Long; /* static Long cast(uint64_t); */ }; |
83 | |
84 | // CToReactorPtr<T>::type resolves to the corresponding Reactor Pointer<> |
85 | // type for T*. |
86 | // For T types that have a CToReactorT<> specialization, |
87 | // CToReactorPtr<T>::type resolves to Pointer< CToReactorT<T> >, otherwise |
88 | // CToReactorPtr<T>::type resolves to Pointer<Byte>. |
89 | template<typename T, typename ENABLE = void> struct CToReactorPtr |
90 | { |
91 | using type = Pointer<Byte>; |
92 | static inline type cast(const T* v); // implemented in Traits.inl |
93 | }; |
94 | |
95 | // CToReactorPtr specialization for T types that have a CToReactorT<> |
96 | // specialization. |
97 | template<typename T> struct CToReactorPtr<T, typename std::enable_if< IsDefined< CToReactorT<T> >::value>::type > |
98 | { |
99 | using type = Pointer< CToReactorT<T> >; |
100 | static inline type cast(const T* v); // implemented in Traits.inl |
101 | }; |
102 | |
103 | // CToReactorPtr specialization for void*. |
104 | // Maps to Pointer<Byte> instead of Pointer<Void>. |
105 | template<> struct CToReactorPtr<void, void> |
106 | { |
107 | using type = Pointer<Byte>; |
108 | static inline type cast(const void* v); // implemented in Traits.inl |
109 | }; |
110 | |
111 | // CToReactorPtr specialization for function pointer types. |
112 | // Maps to Pointer<Byte>. |
113 | // Drops the 'const' qualifier from the cast() method to avoid warnings |
114 | // about const having no meaning for function types. |
115 | template<typename T> struct CToReactorPtr<T, typename std::enable_if< std::is_function<T>::value >::type > |
116 | { |
117 | using type = Pointer<Byte>; |
118 | static inline type cast(T* v); // implemented in Traits.inl |
119 | }; |
120 | |
121 | template<typename T> using CToReactorPtrT = typename CToReactorPtr<T>::type; |
122 | |
123 | // CToReactor specialization for pointer types. |
124 | // For T types that have a CToReactorT<> specialization, |
125 | // CToReactorT<T*>::type resolves to Pointer< CToReactorT<T> >, otherwise |
126 | // CToReactorT<T*>::type resolves to Pointer<Byte>. |
127 | template<typename T> |
128 | struct CToReactor<T, typename std::enable_if<std::is_pointer<T>::value>::type> |
129 | { |
130 | using elem = typename std::remove_pointer<T>::type; |
131 | using type = CToReactorPtrT<elem>; |
132 | static inline type cast(T v); // implemented in Traits.inl |
133 | }; |
134 | |
135 | // CToReactor specialization for enum types. |
136 | template<typename T> |
137 | struct CToReactor<T, typename std::enable_if<std::is_enum<T>::value>::type> |
138 | { |
139 | using underlying = typename std::underlying_type<T>::type; |
140 | using type = CToReactorT<underlying>; |
141 | static type cast(T v); // implemented in Traits.inl |
142 | }; |
143 | |
144 | // IsRValue::value is true if T is of type RValue<X>, where X is any type. |
145 | template <typename T, typename Enable = void> struct IsRValue { static constexpr bool value = false; }; |
146 | template <typename T> struct IsRValue<T, typename std::enable_if<IsDefined<typename T::rvalue_underlying_type>::value>::type> { static constexpr bool value = true; }; |
147 | |
148 | // IsLValue::value is true if T is of, or derives from type LValue<T>. |
149 | template <typename T> struct IsLValue { static constexpr bool value = std::is_base_of<LValue<T>, T>::value; }; |
150 | |
151 | // IsReference::value is true if T is of type Reference<X>, where X is any type. |
152 | template <typename T, typename Enable = void> struct IsReference { static constexpr bool value = false; }; |
153 | template <typename T> struct IsReference<T, typename std::enable_if<IsDefined<typename T::reference_underlying_type>::value>::type> { static constexpr bool value = true; }; |
154 | |
155 | // ReactorTypeT<T> returns the LValue Reactor type for T. |
156 | // T can be a C-type, RValue or LValue. |
157 | template<typename T, typename ENABLE = void> struct ReactorType; |
158 | template<typename T> using ReactorTypeT = typename ReactorType<T>::type; |
159 | template<typename T> struct ReactorType<T, typename std::enable_if<IsDefined<CToReactorT<T>>::value>::type> |
160 | { |
161 | using type = CToReactorT<T>; |
162 | static type cast(T v) { return CToReactor<T>::cast(v); } |
163 | }; |
164 | template<typename T> struct ReactorType<T, typename std::enable_if<IsRValue<T>::value>::type> |
165 | { |
166 | using type = typename T::rvalue_underlying_type; |
167 | static type cast(T v) { return type(v); } |
168 | }; |
169 | template<typename T> struct ReactorType<T, typename std::enable_if<IsLValue<T>::value>::type> |
170 | { |
171 | using type = T; |
172 | static type cast(T v) { return type(v); } |
173 | }; |
174 | template<typename T> struct ReactorType<T, typename std::enable_if<IsReference<T>::value>::type> |
175 | { |
176 | using type = T; |
177 | static type cast(T v) { return type(v); } |
178 | }; |
179 | |
180 | |
181 | // Reactor types that can be used as a return type for a function. |
182 | template <typename T> struct CanBeUsedAsReturn { static constexpr bool value = false; }; |
183 | template <> struct CanBeUsedAsReturn<Void> { static constexpr bool value = true; }; |
184 | template <> struct CanBeUsedAsReturn<Int> { static constexpr bool value = true; }; |
185 | template <> struct CanBeUsedAsReturn<UInt> { static constexpr bool value = true; }; |
186 | template <> struct CanBeUsedAsReturn<Float> { static constexpr bool value = true; }; |
187 | template <typename T> struct CanBeUsedAsReturn<Pointer<T>> { static constexpr bool value = true; }; |
188 | |
189 | // Reactor types that can be used as a parameter types for a function. |
190 | template <typename T> struct CanBeUsedAsParameter { static constexpr bool value = false; }; |
191 | template <> struct CanBeUsedAsParameter<Int> { static constexpr bool value = true; }; |
192 | template <> struct CanBeUsedAsParameter<UInt> { static constexpr bool value = true; }; |
193 | template <> struct CanBeUsedAsParameter<Float> { static constexpr bool value = true; }; |
194 | template <typename T> struct CanBeUsedAsParameter<Pointer<T>> { static constexpr bool value = true; }; |
195 | |
196 | // AssertParameterTypeIsValid statically asserts that all template parameter |
197 | // types can be used as a Reactor function parameter. |
198 | template<typename T, typename ... other> |
199 | struct AssertParameterTypeIsValid : AssertParameterTypeIsValid<other...> |
200 | { |
201 | static_assert(CanBeUsedAsParameter<T>::value, "Invalid parameter type" ); |
202 | }; |
203 | template<typename T> |
204 | struct AssertParameterTypeIsValid<T> |
205 | { |
206 | static_assert(CanBeUsedAsParameter<T>::value, "Invalid parameter type" ); |
207 | }; |
208 | |
209 | // AssertFunctionSignatureIsValid statically asserts that the Reactor |
210 | // function signature is valid. |
211 | template<typename Return, typename... Arguments> |
212 | class AssertFunctionSignatureIsValid; |
213 | template<typename Return> |
214 | class AssertFunctionSignatureIsValid<Return(Void)> {}; |
215 | template<typename Return, typename... Arguments> |
216 | class AssertFunctionSignatureIsValid<Return(Arguments...)> |
217 | { |
218 | static_assert(CanBeUsedAsReturn<Return>::value, "Invalid return type" ); |
219 | static_assert(sizeof(AssertParameterTypeIsValid<Arguments...>) >= 0, "" ); |
220 | }; |
221 | |
222 | } // namespace rr |
223 | |
224 | #endif // rr_Traits_hpp |
225 | |