1 ///////////////////////////////////////////////////////////////////////////// 2 // Copyright (c) Electronic Arts Inc. All rights reserved. 3 ///////////////////////////////////////////////////////////////////////////// 4 5 6 #ifndef EASTL_INTERNAL_TYPE_TRANFORMATIONS_H 7 #define EASTL_INTERNAL_TYPE_TRANFORMATIONS_H 8 9 10 #include <EABase/eabase.h> 11 #if defined(EA_PRAGMA_ONCE_SUPPORTED) 12 #pragma once 13 #endif 14 15 #include <limits.h> 16 17 18 namespace eastl 19 { 20 21 /////////////////////////////////////////////////////////////////////// 22 // add_const 23 // 24 // Add const to a type. 25 // 26 // Tor a given type T, add_const<T>::type is equivalent to T 27 // const if is_const<T>::value == false, and 28 // - is_void<T>::value == true, or 29 // - is_object<T>::value == true. 30 // 31 // Otherwise, add_const<T>::type is equivalent to T. 32 // 33 /////////////////////////////////////////////////////////////////////// 34 35 #define EASTL_TYPE_TRAIT_add_const_CONFORMANCE 1 // add_const is conforming. 36 37 template <typename T, bool = eastl::is_const<T>::value || eastl::is_reference<T>::value || eastl::is_function<T>::value> 38 struct add_const_helper 39 { typedef T type; }; 40 41 template <typename T> 42 struct add_const_helper<T, false> 43 { typedef const T type; }; 44 45 template <typename T> 46 struct add_const 47 { typedef typename eastl::add_const_helper<T>::type type; }; 48 49 // add_const_t is the C++17 using typedef for typename add_const<T>::type. 50 // We provide a backwards-compatible means to access it through a macro for pre-C++11 compilers. 51 #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) 52 #define EASTL_ADD_CONST_T(T) typename add_const<T>::type 53 #else 54 template <typename T> 55 using add_const_t = typename add_const<T>::type; 56 #define EASTL_ADD_CONST_T(T) add_const_t<T> 57 #endif 58 59 60 /////////////////////////////////////////////////////////////////////// 61 // add_volatile 62 // 63 // Add volatile to a type. 64 // 65 // For a given type T, add_volatile<T>::type is equivalent to T volatile 66 // if is_volatile<T>::value == false, and 67 // - is_void<T>::value == true, or 68 // - is_object<T>::value == true. 69 // 70 // Otherwise, add_volatile<T>::type is equivalent to T. 71 // 72 /////////////////////////////////////////////////////////////////////// 73 74 #define EASTL_TYPE_TRAIT_add_volatile_CONFORMANCE 1 // add_volatile is conforming. 75 76 template <typename T, bool = eastl::is_volatile<T>::value || eastl::is_reference<T>::value || eastl::is_function<T>::value> 77 struct add_volatile_helper 78 { typedef T type; }; 79 80 template <typename T> 81 struct add_volatile_helper<T, false> 82 { typedef volatile T type; }; 83 84 template <typename T> struct add_volatile 85 { typedef typename eastl::add_volatile_helper<T>::type type; }; 86 87 template <class T> using add_volatile_t = typename add_volatile<T>::type; 88 89 90 /////////////////////////////////////////////////////////////////////// 91 // add_cv 92 // 93 // The add_cv transformation trait adds const and volatile qualification 94 // to the type to which it is applied. For a given type T, 95 // add_volatile<T>::type is equivalent to add_const<add_volatile<T>::type>::type. 96 // 97 /////////////////////////////////////////////////////////////////////// 98 99 #define EASTL_TYPE_TRAIT_add_cv_CONFORMANCE 1 // add_cv is conforming. 100 101 template<typename T> 102 struct add_cv 103 { 104 typedef typename add_const<typename add_volatile<T>::type>::type type; 105 }; 106 107 template <class T> using add_cv_t = typename add_cv<T>::type; 108 109 110 /////////////////////////////////////////////////////////////////////// 111 // make_signed 112 // 113 // Used to convert an integral type to its signed equivalent, if not already. 114 // T shall be a (possibly const and/or volatile-qualified) integral type 115 // or enumeration but not a bool type.; 116 // 117 // The user can define their own make_signed overrides for their own 118 // types by making a template specialization like done below and adding 119 // it to the user's code. 120 /////////////////////////////////////////////////////////////////////// 121 122 // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and 123 // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types. 124 #define EASTL_TYPE_TRAIT_make_signed_CONFORMANCE 0 // make_signed is only partially conforming. 125 126 template <typename T> struct make_signed { typedef T type; }; 127 128 template <> struct make_signed<unsigned char> { typedef signed char type; }; 129 template <> struct make_signed<const unsigned char> { typedef const signed char type; }; 130 template <> struct make_signed<unsigned short> { typedef signed short type; }; 131 template <> struct make_signed<const unsigned short> { typedef const signed short type; }; 132 template <> struct make_signed<unsigned int> { typedef signed int type; }; 133 template <> struct make_signed<const unsigned int> { typedef const signed int type; }; 134 template <> struct make_signed<unsigned long> { typedef signed long type; }; 135 template <> struct make_signed<const unsigned long> { typedef const signed long type; }; 136 template <> struct make_signed<unsigned long long> { typedef signed long long type; }; 137 template <> struct make_signed<const unsigned long long> { typedef const signed long long type; }; 138 139 #if (defined(CHAR_MAX) && defined(UCHAR_MAX) && (CHAR_MAX == UCHAR_MAX)) // If char is unsigned, we convert char to signed char. However, if char is signed then make_signed returns char itself and not signed char. 140 template <> struct make_signed<char> { typedef signed char type; }; 141 template <> struct make_signed<const char> { typedef signed char type; }; 142 #endif 143 144 #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... 145 #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 4294967295U)) // If wchar_t is a 32 bit unsigned value... 146 template<> 147 struct make_signed<wchar_t> 148 { typedef int32_t type; }; 149 #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 65535)) // If wchar_t is a 16 bit unsigned value... 150 template<> 151 struct make_signed<wchar_t> 152 { typedef int16_t type; }; 153 #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 255)) // If wchar_t is an 8 bit unsigned value... 154 template<> 155 struct make_signed<wchar_t> 156 { typedef int8_t type; }; 157 #endif 158 #endif 159 160 #if EASTL_VARIABLE_TEMPLATES_ENABLED 161 template <class T> 162 using make_signed_t = typename make_signed<T>::type; 163 #endif 164 165 166 /////////////////////////////////////////////////////////////////////// 167 // add_signed 168 // 169 // This is not a C++11 type trait, and is here for backwards compatibility 170 // only. Use the C++11 make_unsigned type trait instead. 171 /////////////////////////////////////////////////////////////////////// 172 173 template<class T> 174 struct add_signed : public make_signed<T> 175 { typedef typename eastl::make_signed<T>::type type; }; 176 177 178 179 180 /////////////////////////////////////////////////////////////////////// 181 // make_unsigned 182 // 183 // Used to convert an integral type to its signed equivalent, if not already. 184 // T shall be a (possibly const and/or volatile-qualified) integral type 185 // or enumeration but not a bool type.; 186 // 187 // The user can define their own make_signed overrides for their own 188 // types by making a template specialization like done below and adding 189 // it to the user's code. 190 /////////////////////////////////////////////////////////////////////// 191 192 // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and 193 // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types. 194 #define EASTL_TYPE_TRAIT_make_unsigned_CONFORMANCE 0 // make_unsigned is only partially conforming. 195 196 template <typename T> struct make_unsigned { typedef T type; }; 197 198 template <> struct make_unsigned<signed char> { typedef unsigned char type; }; 199 template <> struct make_unsigned<const signed char> { typedef const unsigned char type; }; 200 template <> struct make_unsigned<signed short> { typedef unsigned short type; }; 201 template <> struct make_unsigned<const signed short> { typedef const unsigned short type; }; 202 template <> struct make_unsigned<signed int> { typedef unsigned int type; }; 203 template <> struct make_unsigned<const signed int> { typedef const unsigned int type; }; 204 template <> struct make_unsigned<signed long> { typedef unsigned long type; }; 205 template <> struct make_unsigned<const signed long> { typedef const unsigned long type; }; 206 template <> struct make_unsigned<signed long long> { typedef unsigned long long type; }; 207 template <> struct make_unsigned<const signed long long> { typedef const unsigned long long type; }; 208 209 #if (CHAR_MIN < 0) // If char is signed, we convert char to unsigned char. However, if char is unsigned then make_unsigned returns char itself and not unsigned char. 210 template <> struct make_unsigned<char> { typedef unsigned char type; }; 211 template <> struct make_unsigned<const char> { typedef unsigned char type; }; 212 #endif 213 214 #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... 215 #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 4294967295U)) // If wchar_t is a 32 bit signed value... 216 template<> 217 struct make_unsigned<wchar_t> 218 { typedef uint32_t type; }; 219 #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 65535)) // If wchar_t is a 16 bit signed value... 220 template<> 221 struct make_unsigned<wchar_t> 222 { typedef uint16_t type; }; 223 #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 255)) // If wchar_t is an 8 bit signed value... 224 template<> 225 struct make_unsigned<wchar_t> 226 { typedef uint8_t type; }; 227 #endif 228 #endif 229 230 #if EASTL_VARIABLE_TEMPLATES_ENABLED 231 template <class T> 232 using make_unsigned_t = typename make_unsigned<T>::type; 233 #endif 234 235 236 237 /////////////////////////////////////////////////////////////////////// 238 // add_unsigned 239 // 240 // This is not a C++11 type trait, and is here for backwards compatibility 241 // only. Use the C++11 make_unsigned type trait instead. 242 // 243 // Adds unsigned-ness to the given type. 244 // Modifies only integral values; has no effect on others. 245 // add_unsigned<int>::type is unsigned int 246 // add_unsigned<unsigned int>::type is unsigned int 247 // 248 /////////////////////////////////////////////////////////////////////// 249 250 template<class T> 251 struct add_unsigned : public make_unsigned<T> 252 { typedef typename eastl::make_signed<T>::type type; }; 253 254 255 256 /////////////////////////////////////////////////////////////////////// 257 // remove_pointer 258 // 259 // Remove pointer from a type. 260 // 261 // The remove_pointer transformation trait removes top-level indirection 262 // by pointer (if any) from the type to which it is applied. Pointers to 263 // members are not affected. For a given type T, remove_pointer<T*>::type 264 // is equivalent to T. 265 // 266 /////////////////////////////////////////////////////////////////////// 267 268 #define EASTL_TYPE_TRAIT_remove_pointer_CONFORMANCE 1 269 270 template<typename T> struct remove_pointer { typedef T type; }; 271 template<typename T> struct remove_pointer<T*> { typedef T type; }; 272 template<typename T> struct remove_pointer<T* const> { typedef T type; }; 273 template<typename T> struct remove_pointer<T* volatile> { typedef T type; }; 274 template<typename T> struct remove_pointer<T* const volatile> { typedef T type; }; 275 276 #if EASTL_VARIABLE_TEMPLATES_ENABLED 277 template <class T> 278 using remove_pointer_t = typename remove_pointer<T>::type; 279 #endif 280 281 282 /////////////////////////////////////////////////////////////////////// 283 // add_pointer 284 // 285 // Add pointer to a type. 286 // Provides the member typedef type which is the type T*. If T is a 287 // reference type, then type is a pointer to the referred type. 288 // 289 /////////////////////////////////////////////////////////////////////// 290 291 #define EASTL_TYPE_TRAIT_add_pointer_CONFORMANCE 1 292 293 template<class T> 294 struct add_pointer { typedef typename eastl::remove_reference<T>::type* type; }; 295 296 #if EASTL_VARIABLE_TEMPLATES_ENABLED 297 template <class T> 298 using add_pointer_t = typename add_pointer<T>::type; 299 #endif 300 301 302 303 /////////////////////////////////////////////////////////////////////// 304 // remove_extent 305 // 306 // The remove_extent transformation trait removes a dimension from an array. 307 // For a given non-array type T, remove_extent<T>::type is equivalent to T. 308 // For a given array type T[N], remove_extent<T[N]>::type is equivalent to T. 309 // For a given array type const T[N], remove_extent<const T[N]>::type is equivalent to const T. 310 // For example, given a multi-dimensional array type T[M][N], remove_extent<T[M][N]>::type is equivalent to T[N]. 311 /////////////////////////////////////////////////////////////////////// 312 313 #define EASTL_TYPE_TRAIT_remove_extent_CONFORMANCE 1 // remove_extent is conforming. 314 315 template<class T> struct remove_extent { typedef T type; }; 316 template<class T> struct remove_extent<T[]> { typedef T type; }; 317 template<class T, size_t N> struct remove_extent<T[N]> { typedef T type; }; 318 319 #if !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) 320 template <typename T> 321 using remove_extent_t = typename remove_extent<T>::type; 322 #endif 323 324 325 /////////////////////////////////////////////////////////////////////// 326 // remove_all_extents 327 // 328 // The remove_all_extents transformation trait removes all dimensions from an array. 329 // For a given non-array type T, remove_all_extents<T>::type is equivalent to T. 330 // For a given array type T[N], remove_all_extents<T[N]>::type is equivalent to T. 331 // For a given array type const T[N], remove_all_extents<const T[N]>::type is equivalent to const T. 332 // For example, given a multi-dimensional array type T[M][N], remove_all_extents<T[M][N]>::type is equivalent to T. 333 /////////////////////////////////////////////////////////////////////// 334 335 #define EASTL_TYPE_TRAIT_remove_all_extents_CONFORMANCE 1 // remove_all_extents is conforming. 336 337 template<typename T> struct remove_all_extents { typedef T type; }; 338 template<typename T, size_t N> struct remove_all_extents<T[N]> { typedef typename eastl::remove_all_extents<T>::type type; }; 339 template<typename T> struct remove_all_extents<T[]> { typedef typename eastl::remove_all_extents<T>::type type; }; 340 341 #if !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) 342 template <typename T> 343 using remove_all_extents_t = typename remove_all_extents<T>::type; 344 #endif 345 346 347 348 /////////////////////////////////////////////////////////////////////// 349 // aligned_storage 350 // 351 // The aligned_storage transformation trait provides a type that is 352 // suitably aligned to store an object whose size is does not exceed length 353 // and whose alignment is a divisor of alignment. When using aligned_storage, 354 // length must be non-zero, and alignment must >= alignment_of<T>::value 355 // for some type T. We require the alignment value to be a power-of-two. 356 // 357 // GCC versions prior to 4.4 don't properly support this with stack-based 358 // variables. The EABase EA_ALIGN_MAX_AUTOMATIC define identifies the 359 // extent to which stack (automatic) variables can be aligned for the 360 // given compiler/platform combination. 361 // 362 // Example usage: 363 // aligned_storage<sizeof(Widget), alignment_of(Widget)>::type widget; 364 // Widget* pWidget = new(&widget) Widget; 365 // 366 // aligned_storage<sizeof(Widget), 64>::type widgetAlignedTo64; 367 // Widget* pWidget = new(&widgetAlignedTo64) Widget; 368 // 369 // aligned_storage<sizeof(Widget), alignment_of(Widget)>::type widgetArray[37]; 370 // Widget* pWidgetArray = new(widgetArray) Widget[37]; 371 /////////////////////////////////////////////////////////////////////// 372 373 #define EASTL_TYPE_TRAIT_aligned_storage_CONFORMANCE 1 // aligned_storage is conforming. 374 375 #if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4008) 376 // New versions of GCC do not support using 'alignas' with a value greater than 128. 377 // However, this code using the GNU standard alignment attribute works properly. 378 template<size_t N, size_t Align = EASTL_ALIGN_OF(double)> 379 struct aligned_storage 380 { 381 struct type { unsigned char mCharData[N]; } EA_ALIGN(Align); 382 }; 383 #elif (EABASE_VERSION_N >= 20040) && !defined(EA_COMPILER_NO_ALIGNAS) // If C++11 alignas is supported... 384 template<size_t N, size_t Align = EASTL_ALIGN_OF(double)> 385 struct aligned_storage 386 { 387 typedef struct { 388 alignas(Align) unsigned char mCharData[N]; 389 } type; 390 }; 391 392 #elif defined(EA_COMPILER_MSVC) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION < 4007)) || defined(EA_COMPILER_EDG) // At some point GCC fixed their attribute(align) to support non-literals, though it's not clear what version aside from being no later than 4.7 and no earlier than 4.2. 393 // Some compilers don't allow you to to use EA_ALIGNED with anything by a numeric literal, 394 // so we can't use the simpler code like we do further below for other compilers. We support 395 // only up to so much of an alignment value here. 396 template<size_t N, size_t Align> 397 struct aligned_storage_helper { struct type{ unsigned char mCharData[N]; }; }; 398 399 template<size_t N> struct aligned_storage_helper<N, 2> { struct EA_ALIGN( 2) type{ unsigned char mCharData[N]; }; }; 400 template<size_t N> struct aligned_storage_helper<N, 4> { struct EA_ALIGN( 4) type{ unsigned char mCharData[N]; }; }; 401 template<size_t N> struct aligned_storage_helper<N, 8> { struct EA_ALIGN( 8) type{ unsigned char mCharData[N]; }; }; 402 template<size_t N> struct aligned_storage_helper<N, 16> { struct EA_ALIGN( 16) type{ unsigned char mCharData[N]; }; }; 403 template<size_t N> struct aligned_storage_helper<N, 32> { struct EA_ALIGN( 32) type{ unsigned char mCharData[N]; }; }; 404 template<size_t N> struct aligned_storage_helper<N, 64> { struct EA_ALIGN( 64) type{ unsigned char mCharData[N]; }; }; 405 template<size_t N> struct aligned_storage_helper<N, 128> { struct EA_ALIGN( 128) type{ unsigned char mCharData[N]; }; }; 406 template<size_t N> struct aligned_storage_helper<N, 256> { struct EA_ALIGN( 256) type{ unsigned char mCharData[N]; }; }; 407 template<size_t N> struct aligned_storage_helper<N, 512> { struct EA_ALIGN( 512) type{ unsigned char mCharData[N]; }; }; 408 template<size_t N> struct aligned_storage_helper<N, 1024> { struct EA_ALIGN(1024) type{ unsigned char mCharData[N]; }; }; 409 template<size_t N> struct aligned_storage_helper<N, 2048> { struct EA_ALIGN(2048) type{ unsigned char mCharData[N]; }; }; 410 template<size_t N> struct aligned_storage_helper<N, 4096> { struct EA_ALIGN(4096) type{ unsigned char mCharData[N]; }; }; 411 412 template<size_t N, size_t Align = EASTL_ALIGN_OF(double)> 413 struct aligned_storage 414 { 415 typedef typename aligned_storage_helper<N, Align>::type type; 416 }; 417 418 #else 419 template<size_t N, size_t Align = EASTL_ALIGN_OF(double)> 420 struct aligned_storage 421 { 422 union type 423 { 424 unsigned char mCharData[N]; 425 struct EA_ALIGN(Align) mStruct{ }; 426 }; 427 }; 428 #endif 429 430 #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) 431 #define EASTL_ALIGNED_STORAGE_T(N, Align) typename eastl::aligned_storage_t<N, Align>::type 432 #else 433 template <size_t N, size_t Align = EASTL_ALIGN_OF(double)> 434 using aligned_storage_t = typename aligned_storage<N, Align>::type; 435 #define EASTL_ALIGNED_STORAGE_T(N, Align) eastl::aligned_storage_t<N, Align> 436 #endif 437 438 439 440 /////////////////////////////////////////////////////////////////////// 441 // aligned_union 442 // 443 // The member typedef type shall be a POD type suitable for use as 444 // uninitialized storage for any object whose type is listed in Types; 445 // its size shall be at least Len. The static member alignment_value 446 // shall be an integral constant of type std::size_t whose value is 447 // the strictest alignment of all types listed in Types. 448 // Note that the resulting type is not a C/C++ union, but simply memory 449 // block (of pod type) that can be used to placement-new an actual 450 // C/C++ union of the types. The actual union you declare can be a non-POD union. 451 // 452 // Example usage: 453 // union MyUnion { 454 // char c; 455 // int i; 456 // float f; 457 // 458 // MyUnion(float fValue) : f(fValue) {} 459 // }; 460 // 461 // aligned_union<sizeof(MyUnion), char, int, float>::type myUnionStorage; 462 // MyUnion* pMyUnion = new(&myUnionStorage) MyUnion(21.4f); 463 // pMyUnion->i = 37; 464 // 465 /////////////////////////////////////////////////////////////////////// 466 467 #if defined(EA_COMPILER_NO_VARIADIC_TEMPLATES) || !EASTL_TYPE_TRAIT_static_max_CONFORMANCE 468 #define EASTL_TYPE_TRAIT_aligned_union_CONFORMANCE 0 // aligned_union is not conforming, as it supports only a two-member unions. 469 470 // To consider: Expand this to include more possible types. We may want to convert this to be a recursive 471 // template instead of like below. 472 template <size_t minSize, typename Type0, typename Type1 = char, typename Type2 = char, typename Type3 = char> 473 struct aligned_union 474 { 475 static const size_t size0 = eastl::static_max<minSize, sizeof(Type0)>::value; 476 static const size_t size1 = eastl::static_max<size0, sizeof(Type1)>::value; 477 static const size_t size2 = eastl::static_max<size1, sizeof(Type2)>::value; 478 static const size_t size = eastl::static_max<size2, sizeof(Type3)>::value; 479 480 static const size_t alignment0 = eastl::static_max<EA_ALIGN_OF(Type0), EA_ALIGN_OF(Type1)>::value; 481 static const size_t alignment1 = eastl::static_max<alignment0, EA_ALIGN_OF(Type2)>::value; 482 static const size_t alignment_value = eastl::static_max<alignment1, EA_ALIGN_OF(Type3)>::value; 483 484 typedef typename eastl::aligned_storage<size, alignment_value>::type type; 485 }; 486 487 #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) 488 // To do: define macro. 489 #else 490 template <size_t minSize, typename Type0, typename Type1 = char, typename Type2 = char, typename Type3 = char> 491 using aligned_union_t = typename aligned_union<minSize, Type0, Type1, Type2, Type3>::type; 492 #endif 493 #else 494 #define EASTL_TYPE_TRAIT_aligned_union_CONFORMANCE 1 // aligned_union is conforming. 495 496 template <size_t minSize, typename Type0, typename ...TypeN> 497 struct aligned_union 498 { 499 static const size_t size = eastl::static_max<minSize, sizeof(Type0), sizeof(TypeN)...>::value; 500 static const size_t alignment_value = eastl::static_max<EA_ALIGN_OF(Type0), EA_ALIGN_OF(TypeN)...>::value; 501 502 typedef typename eastl::aligned_storage<size, alignment_value>::type type; 503 }; 504 505 #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) 506 // To do: define macro. 507 #else 508 template <size_t minSize, typename... TypeN> 509 using aligned_union_t = typename aligned_union<minSize, TypeN...>::type; 510 #endif 511 512 #endif 513 514 515 /////////////////////////////////////////////////////////////////////// 516 // union_cast 517 // 518 // Safely converts between unrelated types that have a binary equivalency. 519 // This appoach is required by strictly conforming C++ compilers because 520 // directly using a C or C++ cast between unrelated types is fraught with 521 // the possibility of undefined runtime behavior due to type aliasing. 522 // The Source and Dest types must be POD types due to the use of a union 523 // in C++ versions prior to C++11. C++11 relaxes the definition of a POD 524 // such that it allows a classes with trivial default constructors whereas 525 // previous versions did not, so beware of this when writing portable code. 526 // 527 // Example usage: 528 // float f32 = 1.234f; 529 // uint32_t n32 = union_cast<uint32_t>(f32); 530 // 531 // Example possible mis-usage: 532 // The following is valid only if you are aliasing the pointer value and 533 // not what it points to. Most of the time the user intends the latter, 534 // which isn't strictly possible. 535 // Widget* pWidget = CreateWidget(); 536 // Foo* pFoo = union_cast<Foo*>(pWidget); 537 /////////////////////////////////////////////////////////////////////// 538 539 template <typename DestType, typename SourceType> 540 DestType union_cast(SourceType sourceValue) 541 { 542 EASTL_CT_ASSERT((sizeof(DestType) == sizeof(SourceType)) && 543 (EA_ALIGN_OF(DestType) == EA_ALIGN_OF(SourceType))); // To support differening alignments, we would need to use a memcpy-based solution or find a way to make the two union members align with each other. 544 //EASTL_CT_ASSERT(is_pod<DestType>::value && is_pod<SourceType>::value); // Disabled because we don't want to restrict what the user can do, as some compiler's definitions of is_pod aren't up to C++11 Standards. 545 //EASTL_CT_ASSERT(!is_pointer<DestType>::value && !is_pointer<SourceType>::value); // Disabled because it's valid to alias pointers as long as you are aliasong the pointer value and not what it points to. 546 547 union { 548 SourceType sourceValue; 549 DestType destValue; 550 } u; 551 u.sourceValue = sourceValue; 552 553 return u.destValue; 554 } 555 556 557 558 /////////////////////////////////////////////////////////////////////// 559 // void_t 560 // 561 // Maps a sequence of any types to void. This utility class is used in 562 // template meta programming to simplify compile time reflection mechanisms 563 // required by the standard library. 564 // 565 // http://en.cppreference.com/w/cpp/types/void_t 566 // 567 // Example: 568 // template <typename T, typename = void> 569 // struct is_iterable : false_type {}; 570 // 571 // template <typename T> 572 // struct is_iterable<T, void_t<decltype(declval<T>().begin()), 573 // decltype(declval<T>().end())>> : true_type {}; 574 // 575 /////////////////////////////////////////////////////////////////////// 576 #if EASTL_VARIABLE_TEMPLATES_ENABLED 577 template <class...> 578 using void_t = void; 579 #endif 580 581 582 } // namespace eastl 583 584 585 #endif // Header include guard 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607