< prev index next >

src/share/vm/metaprogramming/integerTypes.hpp

Print this page
rev 13456 : [mq]: union_trick

*** 24,40 **** #ifndef SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP #define SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP #include "memory/allocation.hpp" - #include "utilities/debug.hpp" #include "metaprogramming/enableIf.hpp" #include "metaprogramming/integralConstant.hpp" #include "metaprogramming/isFloatingPoint.hpp" - #include "metaprogramming/isPointer.hpp" - #include "metaprogramming/isRegisteredEnum.hpp" #include "metaprogramming/isIntegral.hpp" class IntegerTypes : public AllStatic { public: // Return a value of type T with the same representation as x. // --- 24,39 ---- #ifndef SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP #define SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP #include "memory/allocation.hpp" #include "metaprogramming/enableIf.hpp" #include "metaprogramming/integralConstant.hpp" #include "metaprogramming/isFloatingPoint.hpp" #include "metaprogramming/isIntegral.hpp" + #include "metaprogramming/isRegisteredEnum.hpp" + #include "utilities/debug.hpp" class IntegerTypes : public AllStatic { public: // Return a value of type T with the same representation as x. //
*** 53,158 **** // the same representation as x. // - static T recover(Decayed x): return a value of type T with the // same representation as x. template<typename T> struct Translate : public FalseType {}; - // Value categories. For internal use, but needs to be public. - enum Category { - INTEGRAL, - ENUM, - FLOAT, - POINTER - }; - private: - template<typename T, typename Enable = void> struct GetCategory; - template<typename T, typename U, bool same_size = sizeof(T) == sizeof(U), ! Category to_category = GetCategory<T>::value, ! Category from_category = GetCategory<U>::value> struct Cast; ! template<typename T, typename U> static T cast_integral(U x); ! template<typename T, typename U> static T cast_floating_point(U x); }; ! #define DEFINE_GET_CATEGORY(Predicate, Value) \ ! template<typename T> \ ! struct IntegerTypes::GetCategory< \ ! T, \ ! typename EnableIf<Predicate<T>::value>::type> \ ! : IntegralConstant<IntegerTypes::Category, IntegerTypes::Value> \ ! {}; ! ! DEFINE_GET_CATEGORY(IsIntegral, INTEGRAL) ! DEFINE_GET_CATEGORY(IsRegisteredEnum, ENUM) ! DEFINE_GET_CATEGORY(IsFloatingPoint, FLOAT) ! DEFINE_GET_CATEGORY(IsPointer, POINTER) ! ! #undef DEFINE_GET_CATEGORY ! ! // Convert between different integral types of the same size. ! // See C++03 3.10/15 for discussion of reinterpret_cast to a reference ! // as a means for converting integral types while keeping the representation. ! template<typename T, typename U> ! inline T IntegerTypes::cast_integral(U x) { ! STATIC_ASSERT(sizeof(T) == sizeof(U)); ! return reinterpret_cast<T&>(x); ! } ! ! // Convert between an integral type and a floating point type of the ! // same size. The only truly correct way to do this is with memcpy. ! // Both the union trick and type punning via casts are undefined ! // behavior. gcc generates exactly the same code for all three methods, ! // except where the UB of type punning causes it to go off into the weeds. ! // (gcc explicitly supports the union trick.) Other compilers may vary. ! // In particular, not all compilers do a good job with the memcpy. template<typename T, typename U> ! inline T IntegerTypes::cast_floating_point(U x) { STATIC_ASSERT(sizeof(T) == sizeof(U)); ! T result; ! memcpy(&result, &x, sizeof(x)); ! return result; } ////////////////////////////////////////////////////////////////////////////// // cast<T>(x) // ! // Cast<T, U, same_size, to_category, from_category> // Give an informative error if the sizes differ. ! template<typename T, typename U, ! IntegerTypes::Category to_category, ! IntegerTypes::Category from_category> ! struct IntegerTypes::Cast<T, U, false, to_category, from_category> VALUE_OBJ_CLASS_SPEC { ! STATIC_ASSERT(sizeof(T) == sizeof(U)); }; ! #define DEFINE_INTEGER_TYPES_CAST(To, From, Convert) \ ! template<typename T, typename U> \ ! struct IntegerTypes::Cast<T, U, true, \ ! IntegerTypes::To, \ ! IntegerTypes::From> \ ! VALUE_OBJ_CLASS_SPEC \ ! { \ ! T operator()(U x) const { return Convert<T>(x); } \ ! }; ! ! DEFINE_INTEGER_TYPES_CAST(INTEGRAL, INTEGRAL, cast_integral) ! DEFINE_INTEGER_TYPES_CAST(ENUM, INTEGRAL, cast_integral) ! DEFINE_INTEGER_TYPES_CAST(INTEGRAL, ENUM, cast_integral) ! DEFINE_INTEGER_TYPES_CAST(FLOAT, INTEGRAL, cast_floating_point) ! DEFINE_INTEGER_TYPES_CAST(INTEGRAL, FLOAT, cast_floating_point) ! DEFINE_INTEGER_TYPES_CAST(POINTER, INTEGRAL, reinterpret_cast) ! DEFINE_INTEGER_TYPES_CAST(INTEGRAL, POINTER, reinterpret_cast) ! #undef DEFINE_INTEGER_TYPES_CAST template<typename T, typename U> inline T IntegerTypes::cast(U x) { return Cast<T, U>()(x); } --- 52,168 ---- // the same representation as x. // - static T recover(Decayed x): return a value of type T with the // same representation as x. template<typename T> struct Translate : public FalseType {}; private: template<typename T, typename U, bool same_size = sizeof(T) == sizeof(U), ! typename Enable = void> struct Cast; ! template<typename T, typename U> static T cast_using_union(U x); }; ! // Return an object of type T with the same value representation as x. ! // ! // T and U must be of the same size. It is expected that one of T and ! // U is an integral type, and the other is an integral type, a ! // (registered) enum type, or a floating point type ! // ! // This implementation uses the "union trick", which seems to be the ! // best of a bad set of options. Though technically undefined ! // behavior, it is widely and well supported, producing good code. In ! // some cases, such as gcc, that support is explicitly documented. ! // ! // Using memcpy is the correct method, but some compilers produce ! // wretched code for that method, even at maximal optimization levels. ! // ! // Using static_cast is only possible for integral and enum types, not ! // for floating point types. And for integral and enum conversions, ! // static_cast has unspecified or implementation-defined behavior for ! // some cases. C++11 <type_traits> can be used to avoid most or all ! // of those unspecified or implementation-defined issues, though that ! // may require multi-step conversions. ! // ! // Using reinterpret_cast of references has undefined behavior for ! // many cases, and there is much less empirical basis for its use, as ! // compared to the union trick. template<typename T, typename U> ! inline T IntegerTypes::cast_using_union(U x) { STATIC_ASSERT(sizeof(T) == sizeof(U)); ! union { T t; U u; }; ! u = x; ! return t; } ////////////////////////////////////////////////////////////////////////////// // cast<T>(x) // ! // Cast<T, U, same_size, Enable> // Give an informative error if the sizes differ. ! template<typename T, typename U> ! struct IntegerTypes::Cast<T, U, false> VALUE_OBJ_CLASS_SPEC { ! STATIC_ASSERT(sizeof(T) == sizeof(U)); ! }; ! ! // Conversion between integral types. ! template<typename T, typename U> ! struct IntegerTypes::Cast< ! T, U, true, ! typename EnableIf<IsIntegral<T>::value && IsIntegral<U>::value>::type> VALUE_OBJ_CLASS_SPEC { ! T operator()(U x) const { return cast_using_union<T>(x); } ! }; ! ! // Convert an enum or floating point value to an integer value. ! template<typename T, typename U> ! struct IntegerTypes::Cast< ! T, U, true, ! typename EnableIf<IsIntegral<T>::value && ! (IsRegisteredEnum<U>::value || ! IsFloatingPoint<U>::value)>::type> ! VALUE_OBJ_CLASS_SPEC ! { ! T operator()(U x) const { return cast_using_union<T>(x); } }; ! // Convert an integer to an enum or floating point value. ! template<typename T, typename U> ! struct IntegerTypes::Cast< ! T, U, true, ! typename EnableIf<IsIntegral<U>::value && ! (IsRegisteredEnum<T>::value || ! IsFloatingPoint<T>::value)>::type> ! VALUE_OBJ_CLASS_SPEC ! { ! T operator()(U x) const { return cast_using_union<T>(x); } ! }; ! // Convert a pointer to an integral value. ! template<typename T, typename U> ! struct IntegerTypes::Cast< ! T, U*, true, ! typename EnableIf<IsIntegral<T>::value>::type> ! VALUE_OBJ_CLASS_SPEC ! { ! T operator()(U* x) const { return reinterpret_cast<T>(x); } ! }; ! ! // Convert an integral value to a pointer. ! template<typename T, typename U> ! struct IntegerTypes::Cast< ! T*, U, true, ! typename EnableIf<IsIntegral<U>::value>::type> ! VALUE_OBJ_CLASS_SPEC ! { ! T* operator()(U x) const { return reinterpret_cast<T*>(x); } ! }; template<typename T, typename U> inline T IntegerTypes::cast(U x) { return Cast<T, U>()(x); }
< prev index next >