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