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
25namespace 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