1 /*
2  * Copyright (C) 2016 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 STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
18 #define STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
19 
20 #include <type_traits>
21 
22 #undef HIDE
23 #define HIDE __attribute__((visibility("hidden")))
24 
25 namespace android {
26 
27 /**
28  * std::is_signed, is_unsigned and is_integral does not consider enums even though the standard
29  * considers them integral. Create modified versions of these here. Also create a wrapper around
30  * std::underlying_type that does not require checking if the type is an enum.
31  */
32 
33 /**
34  * Type support utility class to check if a type is an integral type or an enum.
35  */
36 template<typename T>
37 struct HIDE is_integral_or_enum
38     : std::integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value> { };
39 
40 /**
41  * Type support utility class to get the underlying std::is_integral supported type for a type.
42  * This returns the underlying type for enums, and the same type for types covered by
43  * std::is_integral.
44  *
45  * This is also used as a conditional to return an alternate type if the template param is not
46  * an integral or enum type (as in underlying_integral_type<T, TypeIfNotEnumOrIntegral>::type).
47  */
48 template<typename T,
49         typename U=typename std::enable_if<is_integral_or_enum<T>::value>::type,
50         bool=std::is_enum<T>::value,
51         bool=std::is_integral<T>::value>
52 struct HIDE underlying_integral_type {
53     static_assert(!std::is_enum<T>::value, "T should not be enum here");
54     static_assert(!std::is_integral<T>::value, "T should not be integral here");
55     typedef U type;
56 };
57 
58 /** Specialization for enums. */
59 template<typename T, typename U>
60 struct HIDE underlying_integral_type<T, U, true, false> {
61     static_assert(std::is_enum<T>::value, "T should be enum here");
62     static_assert(!std::is_integral<T>::value, "T should not be integral here");
63     typedef typename std::underlying_type<T>::type type;
64 };
65 
66 /** Specialization for non-enum std-integral types. */
67 template<typename T, typename U>
68 struct HIDE underlying_integral_type<T, U, false, true> {
69     static_assert(!std::is_enum<T>::value, "T should not be enum here");
70     static_assert(std::is_integral<T>::value, "T should be integral here");
71     typedef T type;
72 };
73 
74 /**
75  * Type support utility class to check if the underlying integral type is signed.
76  */
77 template<typename T>
78 struct HIDE is_signed_integral
79     : std::integral_constant<bool, std::is_signed<
80             typename underlying_integral_type<T, unsigned>::type>::value> { };
81 
82 /**
83  * Type support utility class to check if the underlying integral type is unsigned.
84  */
85 template<typename T>
86 struct HIDE is_unsigned_integral
87     : std::integral_constant<bool, std::is_unsigned<
88             typename underlying_integral_type<T, signed>::type>::value> {
89 };
90 
91 /**
92  * Type support relationship query template.
93  *
94  * If T occurs as one of the types in Us with the same const-volatile qualifications, provides the
95  * member constant |value| equal to true. Otherwise value is false.
96  */
97 template<typename T, typename ...Us>
98 struct HIDE is_one_of;
99 
100 /// \if 0
101 /**
102  * Template specialization when first type matches the searched type.
103  */
104 template<typename T, typename ...Us>
105 struct HIDE is_one_of<T, T, Us...> : std::true_type {};
106 
107 /**
108  * Template specialization when first type does not match the searched type.
109  */
110 template<typename T, typename U, typename ...Us>
111 struct HIDE is_one_of<T, U, Us...> : is_one_of<T, Us...> {};
112 
113 /**
114  * Template specialization when there are no types to search.
115  */
116 template<typename T>
117 struct HIDE is_one_of<T> : std::false_type {};
118 /// \endif
119 
120 /**
121  * Type support relationship query template.
122  *
123  * If all types in Us are unique, provides the member constant |value| equal to true.
124  * Otherwise value is false.
125  */
126 template<typename ...Us>
127 struct HIDE are_unique;
128 
129 /// \if 0
130 /**
131  * Template specialization when there are no types.
132  */
133 template<>
134 struct HIDE are_unique<> : std::true_type {};
135 
136 /**
137  * Template specialization when there is at least one type to check.
138  */
139 template<typename T, typename ...Us>
140 struct HIDE are_unique<T, Us...>
141     : std::integral_constant<bool, are_unique<Us...>::value && !is_one_of<T, Us...>::value> {};
142 /// \endif
143 
144 /// \if 0
145 template<size_t Base, typename T, typename ...Us>
146 struct HIDE _find_first_impl;
147 
148 /**
149  * Template specialization when there are no types to search.
150  */
151 template<size_t Base, typename T>
152 struct HIDE _find_first_impl<Base, T> : std::integral_constant<size_t, 0> {};
153 
154 /**
155  * Template specialization when T is the first type in Us.
156  */
157 template<size_t Base, typename T, typename ...Us>
158 struct HIDE _find_first_impl<Base, T, T, Us...> : std::integral_constant<size_t, Base> {};
159 
160 /**
161  * Template specialization when T is not the first type in Us.
162  */
163 template<size_t Base, typename T, typename U, typename ...Us>
164 struct HIDE _find_first_impl<Base, T, U, Us...>
165     : std::integral_constant<size_t, _find_first_impl<Base + 1, T, Us...>::value> {};
166 
167 /// \endif
168 
169 /**
170  * Type support relationship query template.
171  *
172  * If T occurs in Us, index is the 1-based left-most index of T in Us. Otherwise, index is 0.
173  */
174 template<typename T, typename ...Us>
175 struct HIDE find_first {
176     static constexpr size_t index = _find_first_impl<1, T, Us...>::value;
177 };
178 
179 /// \if 0
180 /**
181  * Helper class for find_first_convertible_to template.
182  *
183  * Adds a base index.
184  */
185 template<size_t Base, typename T, typename ...Us>
186 struct HIDE _find_first_convertible_to_helper;
187 
188 /**
189  * Template specialization for when there are more types to consider
190  */
191 template<size_t Base, typename T, typename U, typename ...Us>
192 struct HIDE _find_first_convertible_to_helper<Base, T, U, Us...> {
193     static constexpr size_t index =
194         std::is_convertible<T, U>::value ? Base :
195                 _find_first_convertible_to_helper<Base + 1, T, Us...>::index;
196     typedef typename std::conditional<
197         std::is_convertible<T, U>::value, U,
198         typename _find_first_convertible_to_helper<Base + 1, T, Us...>::type>::type type;
199 };
200 
201 /**
202  * Template specialization for when there are no more types to consider
203  */
204 template<size_t Base, typename T>
205 struct HIDE _find_first_convertible_to_helper<Base, T> {
206     static constexpr size_t index = 0;
207     typedef void type;
208 };
209 
210 /// \endif
211 
212 /**
213  * Type support template that returns the type that T can be implicitly converted into, and its
214  * index, from a list of other types (Us).
215  *
216  * Returns index of 0 and type of void if there are no convertible types.
217  *
218  * \param T type that is converted
219  * \param Us types into which the conversion is considered
220  */
221 template<typename T, typename ...Us>
222 struct HIDE find_first_convertible_to : public _find_first_convertible_to_helper<1, T, Us...> { };
223 
224 }  // namespace android
225 
226 #endif  // STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
227 
228