1 // Copyright 2016 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 namespace fbl { 8 9 template <typename T, T v> 10 struct integral_constant { 11 static constexpr T value = v; 12 13 using value_type = T; 14 using type = integral_constant<T, v>; 15 }; 16 17 using true_type = integral_constant<bool, true>; 18 using false_type = integral_constant<bool, false>; 19 20 // is_void: 21 template <typename T> 22 struct is_void : false_type {}; 23 24 template <> 25 struct is_void<void> : true_type {}; 26 27 template <> 28 struct is_void<const void> : true_type {}; 29 30 template <> 31 struct is_void<volatile void> : true_type {}; 32 33 template <> 34 struct is_void<const volatile void> : true_type {}; 35 36 // is_null_pointer: 37 template <typename T> 38 struct is_null_pointer : false_type {}; 39 40 template <> 41 struct is_null_pointer<decltype(nullptr)> : true_type {}; 42 43 template <> 44 struct is_null_pointer<const decltype(nullptr)> : true_type {}; 45 46 template <> 47 struct is_null_pointer<volatile decltype(nullptr)> : true_type {}; 48 49 template <> 50 struct is_null_pointer<const volatile decltype(nullptr)> : true_type {}; 51 52 // is_const: 53 54 template <typename T> 55 struct is_const : false_type {}; 56 57 template <typename T> 58 struct is_const<const T> : true_type {}; 59 60 // is_lvalue_reference: 61 62 template <typename T> 63 struct is_lvalue_reference : false_type {}; 64 65 template <typename T> 66 struct is_lvalue_reference<T&> : true_type {}; 67 68 // is_rvalue_reference: 69 70 template <typename T> 71 struct is_rvalue_reference : false_type {}; 72 73 template <typename T> 74 struct is_rvalue_reference<T&&> : true_type {}; 75 76 // is_reference: 77 template <typename T> 78 struct is_reference : false_type {}; 79 80 template <typename T> 81 struct is_reference<T&> : true_type {}; 82 83 template <typename T> 84 struct is_reference<T&&> : true_type {}; 85 86 // remove_reference: 87 88 template <typename T> 89 struct remove_reference { 90 using type = T; 91 }; 92 93 template <typename T> 94 struct remove_reference<T&> { 95 using type = T; 96 }; 97 98 template <typename T> 99 struct remove_reference<T&&> { 100 using type = T; 101 }; 102 103 // remove_pointer: 104 105 template <typename T> 106 struct remove_pointer { 107 using type = T; 108 }; 109 110 template <typename T> 111 struct remove_pointer<T*> { 112 using type = T; 113 }; 114 115 // remove_const: 116 117 template <typename T> 118 struct remove_const { 119 typedef T type; 120 }; 121 122 template <typename T> 123 struct remove_const<const T> { 124 typedef T type; 125 }; 126 127 // remove_volatile: 128 129 template <typename T> 130 struct remove_volatile { 131 typedef T type; 132 }; 133 134 template <typename T> 135 struct remove_volatile<volatile T> { 136 typedef T type; 137 }; 138 139 // remove_cv: 140 141 template <typename T> 142 struct remove_cv { 143 typedef typename remove_volatile<typename remove_const<T>::type>::type type; 144 }; 145 146 // remove_extent: 147 148 template <typename T> 149 struct remove_extent { 150 using type = T; 151 }; 152 153 template <typename T> 154 struct remove_extent<T[]> { 155 using type = T; 156 }; 157 158 // Avoid having to pull in a header to name size_t; just use sizeof to 159 // get at it. 160 template <typename T, decltype(sizeof(nullptr)) N> 161 struct remove_extent<T[N]> { 162 using type = T; 163 }; 164 165 // forward: 166 167 template <typename T> 168 constexpr T&& forward(typename remove_reference<T>::type& t) { 169 return static_cast<T&&>(t); 170 } 171 172 template <typename T> 173 constexpr T&& forward(typename remove_reference<T>::type&& t) { 174 static_assert(!is_lvalue_reference<T>::value, "bad fbl::forward call"); 175 return static_cast<T&&>(t); 176 } 177 178 // is_same: 179 180 template<class T, class U> struct is_same : false_type {}; 181 template<class T> struct is_same<T, T> : true_type {}; 182 183 // enable_if: 184 185 template<bool B, class T = void> struct enable_if { }; 186 template<class T> struct enable_if<true, T> { 187 typedef T type; 188 }; 189 190 // conditional: 191 192 template<bool B, class T, class F> 193 struct conditional { typedef T type; }; 194 195 template<class T, class F> 196 struct conditional<false, T, F> { typedef F type; }; 197 198 // is_integral. By default, T is not integral (aka, not an integer) 199 template <typename T> 200 struct is_integral : false_type {}; 201 202 // Specializations. Every basic integral type needs to be called out. 203 template <> struct is_integral<bool> : true_type {}; 204 template <> struct is_integral<char> : true_type {}; 205 template <> struct is_integral<char16_t> : true_type {}; 206 template <> struct is_integral<char32_t> : true_type {}; 207 template <> struct is_integral<wchar_t> : true_type {}; 208 template <> struct is_integral<signed char> : true_type {}; 209 template <> struct is_integral<unsigned char> : true_type {}; 210 template <> struct is_integral<short int> : true_type {}; 211 template <> struct is_integral<unsigned short int> : true_type {}; 212 template <> struct is_integral<int> : true_type {}; 213 template <> struct is_integral<unsigned int> : true_type {}; 214 template <> struct is_integral<long int> : true_type {}; 215 template <> struct is_integral<unsigned long int> : true_type {}; 216 template <> struct is_integral<long long int> : true_type {}; 217 template <> struct is_integral<unsigned long long int> : true_type {}; 218 219 // is_floating_point. By default, T is not a floating point type. 220 template <typename T> 221 struct is_floating_point : false_type {}; 222 223 // Specializations. Every basic floating point type needs to be called out. 224 template <> struct is_floating_point<float> : true_type {}; 225 template <> struct is_floating_point<double> : true_type {}; 226 template <> struct is_floating_point<long double> : true_type {}; 227 228 // Arithmetic data types are either floats or integers 229 template <typename T> 230 struct is_arithmetic : 231 integral_constant<bool, is_integral<T>::value || is_floating_point<T>::value> { }; 232 233 namespace internal { 234 235 template<typename T, bool = is_arithmetic<T>::value> 236 struct is_signed : integral_constant<bool, T(-1) < T(0)> {}; 237 template<typename T> 238 struct is_signed<T, false> : fbl::false_type {}; 239 240 template<typename T, bool = is_arithmetic<T>::value> 241 struct is_unsigned : integral_constant<bool, T(0) < T(-1)> {}; 242 template<typename T> 243 struct is_unsigned<T, false> : fbl::false_type {}; 244 245 template<typename T, bool = is_integral<T>::value> 246 struct is_signed_integer : integral_constant<bool, T(-1) < T(0)> {}; 247 template<typename T> 248 struct is_signed_integer<T, false> : fbl::false_type {}; 249 250 template<typename T, bool = is_integral<T>::value> 251 struct is_unsigned_integer : integral_constant<bool, T(0) < T(-1)> {}; 252 template<typename T> 253 struct is_unsigned_integer<T, false> : fbl::false_type {}; 254 255 } // namespace internal 256 257 template <typename T> 258 struct is_signed : internal::is_signed<T>::type {}; 259 260 template <typename T> 261 struct is_unsigned : internal::is_unsigned<T>::type {}; 262 263 template <typename T> 264 struct is_signed_integer : internal::is_signed_integer<T>::type {}; 265 266 template <typename T> 267 struct is_unsigned_integer : internal::is_unsigned_integer<T>::type {}; 268 269 // is_enum is a builtin 270 template<typename T> 271 struct is_enum : integral_constant<bool, __is_enum(T)> { }; 272 273 // is_pod is a builtin 274 template<typename T> 275 struct is_pod : integral_constant<bool, __is_pod(T)> { }; 276 277 // is_standard_layout is a builtin 278 template<typename T> 279 struct is_standard_layout : integral_constant<bool, __is_standard_layout(T)> { }; 280 281 // underlying_type is a builtin 282 template<typename T> 283 struct underlying_type { 284 using type = __underlying_type(T); 285 }; 286 287 // match_cv: match_cv<SrcType, DestType>::type is DestType cv-qualified in the same way as SrcType. 288 289 // Primary template: 290 template <typename SrcType, typename DestType> 291 struct match_cv { 292 using type = typename remove_cv<DestType>::type; 293 }; 294 295 // Specializations for const/volatile/const volatile: 296 template <typename SrcType, typename DestType> 297 struct match_cv<const SrcType, DestType> { 298 using type = typename remove_cv<DestType>::type const; 299 }; 300 template <typename SrcType, typename DestType> 301 struct match_cv<volatile SrcType, DestType> { 302 using type = typename remove_cv<DestType>::type volatile; 303 }; 304 template <typename SrcType, typename DestType> 305 struct match_cv<const volatile SrcType, DestType> { 306 using type = typename remove_cv<DestType>::type const volatile; 307 }; 308 309 // is_class builtin 310 template <typename T> 311 struct is_class : public integral_constant<bool, __is_class(T)> { }; 312 313 // is_union builtin 314 template <typename T> 315 struct is_union : public integral_constant<bool, __is_union(T)> { }; 316 317 // is_base_of builtin 318 template <typename Base, typename Derived> 319 struct is_base_of : public integral_constant<bool, __is_base_of(Base, Derived)> { }; 320 321 // has_virtual_destructor 322 template <typename T> 323 struct has_virtual_destructor : public integral_constant<bool, __has_virtual_destructor(T)> { }; 324 325 // has_trivial_destructor 326 template <typename T> 327 struct has_trivial_destructor : public integral_constant<bool, __has_trivial_destructor(T)> { }; 328 329 // is_pointer 330 namespace internal { 331 template <typename T> 332 struct is_pointer : public false_type { }; 333 334 template <typename T> 335 struct is_pointer<T*> : public true_type { }; 336 } // namespace internal 337 338 template <typename T> 339 struct is_pointer : 340 public integral_constant<bool, 341 internal::is_pointer<typename remove_cv<T>::type>::value> { }; 342 343 // is_convertible_pointer 344 // 345 // Note: this is a simplified version of std::is_convertible. Whereas 346 // std::is_convertible will check to see if any two types are implicitly 347 // convertible, is_convertible_pointer will only check to see if two pointer 348 // types are implicitly convertible. Additionally, no explicit support or tests 349 // have been added for function pointers conversion. 350 template <typename From, typename To> 351 struct is_convertible_pointer { 352 private: 353 static true_type test(To); 354 static false_type test(...); 355 static From make_from_type(); 356 357 public: 358 static constexpr bool value = 359 is_pointer<From>::value && 360 is_pointer<To>::value && 361 decltype(test(make_from_type()))::value; 362 }; 363 364 namespace internal { 365 366 template <typename...> 367 struct make_void { 368 using type = void; 369 }; 370 371 } // namespace internal 372 373 // Utility type for SFINAE expression evaluation, equivalent to C++17 std::void_t. 374 template <typename... Ts> 375 using void_t = typename internal::make_void<Ts...>::type; 376 377 // is_function: 378 379 // Morally, is_function could be implemented in the same style as 380 // e.g. is_reference: a base case of false, and specializations of 381 // true for every kind of function. However, listing all of those 382 // cases is brittle and language version dependent. For instance, 383 // C++17 makes noexcept specifiers as part of the type. 384 385 // Instead, this implementation uses a pair of tricky overloaded 386 // functions to detect every type that _isn't_ a function. This 387 // includes: 388 // - objects (classes, unions, and primitives) (including incomplete types) 389 // - references (including references to functions) 390 // - nullptr_t 391 // - void 392 // - pointers (including pointers to functions) 393 // - pointers to members 394 // - arrays of both complete and incomplete type 395 396 namespace internal { 397 398 // This leaves pointers, pointer-to-members, arrays, and functions. 399 template <typename T> 400 struct is_object_void_reference_or_null_pointer { 401 static constexpr bool value = 402 is_class<T>::value || 403 is_union<T>::value || 404 is_void<T>::value || 405 is_reference<T>::value || 406 is_null_pointer<T>::value; 407 }; 408 409 struct dummy {}; 410 411 struct func_tag {}; 412 413 struct nonfunc_tag {}; 414 415 template <typename T> 416 func_tag choose(T*); 417 418 template <typename T> 419 func_tag choose(dummy); 420 421 template <typename T> 422 nonfunc_tag choose(...); 423 424 template <typename T> 425 T& make(int); 426 427 template <typename T> 428 dummy make(...); 429 430 } // namespace internal 431 432 template <typename T, 433 bool = internal::is_object_void_reference_or_null_pointer<T>::value> 434 struct is_function : public integral_constant<bool, 435 is_same<internal::func_tag, 436 decltype(internal::choose<T>(internal::make<T>(0))) 437 >::value> { 438 }; 439 440 template <typename T> 441 struct is_function<T, true> : public false_type { 442 }; 443 444 } // namespace fbl 445