< prev index next >

src/share/vm/metaprogramming/integerTypes.hpp

Print this page
rev 13456 : [mq]: union_trick


   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP
  26 #define SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP
  27 
  28 #include "memory/allocation.hpp"
  29 #include "utilities/debug.hpp"
  30 #include "metaprogramming/enableIf.hpp"
  31 #include "metaprogramming/integralConstant.hpp"
  32 #include "metaprogramming/isFloatingPoint.hpp"
  33 #include "metaprogramming/isPointer.hpp"
  34 #include "metaprogramming/isRegisteredEnum.hpp"
  35 #include "metaprogramming/isIntegral.hpp"


  36 
  37 class IntegerTypes : public AllStatic {
  38 public:
  39   // Return a value of type T with the same representation as x.
  40   //
  41   // T and U must be of the same size.
  42   //
  43   // At least one of T or U must be an integral type.  The other must
  44   // be an integral, floating point, or pointer type.
  45   template<typename T, typename U> static T cast(U x);
  46 
  47   // Support thin wrappers over primitive types.
  48   // If derived from TrueType, provides representational conversion
  49   // from T to some other type.  When true, must provide
  50   // - Value: typedef for T.
  51   // - Decayed: typedef for decayed type.
  52   // - static Decayed decay(T x): return value of type Decayed with
  53   //   the same representation as x.
  54   // - static T recover(Decayed x): return a value of type T with the
  55   //   same representation as x.
  56   template<typename T> struct Translate : public FalseType {};
  57 
  58   // Value categories.  For internal use, but needs to be public.
  59   enum Category {
  60     INTEGRAL,
  61     ENUM,
  62     FLOAT,
  63     POINTER
  64   };
  65 
  66 private:
  67 
  68   template<typename T, typename Enable = void> struct GetCategory;
  69 
  70   template<typename T,
  71            typename U,
  72            bool same_size = sizeof(T) == sizeof(U),
  73            Category to_category = GetCategory<T>::value,
  74            Category from_category = GetCategory<U>::value>
  75   struct Cast;
  76 
  77   template<typename T, typename U> static T cast_integral(U x);
  78   template<typename T, typename U> static T cast_floating_point(U x);
  79 };
  80 
  81 #define DEFINE_GET_CATEGORY(Predicate, Value)                           \
  82   template<typename T>                                                  \
  83   struct IntegerTypes::GetCategory<                                     \
  84     T,                                                                  \
  85     typename EnableIf<Predicate<T>::value>::type>                       \
  86     : IntegralConstant<IntegerTypes::Category, IntegerTypes::Value>     \
  87   {};
  88 
  89 DEFINE_GET_CATEGORY(IsIntegral, INTEGRAL)
  90 DEFINE_GET_CATEGORY(IsRegisteredEnum, ENUM)
  91 DEFINE_GET_CATEGORY(IsFloatingPoint, FLOAT)
  92 DEFINE_GET_CATEGORY(IsPointer, POINTER)
  93 
  94 #undef DEFINE_GET_CATEGORY
  95 
  96 // Convert between different integral types of the same size.
  97 // See C++03 3.10/15 for discussion of reinterpret_cast to a reference
  98 // as a means for converting integral types while keeping the representation.
  99 template<typename T, typename U>
 100 inline T IntegerTypes::cast_integral(U x) {
 101   STATIC_ASSERT(sizeof(T) == sizeof(U));
 102   return reinterpret_cast<T&>(x);
 103 }
 104 
 105 // Convert between an integral type and a floating point type of the
 106 // same size.  The only truly correct way to do this is with memcpy.
 107 // Both the union trick and type punning via casts are undefined
 108 // behavior. gcc generates exactly the same code for all three methods,
 109 // except where the UB of type punning causes it to go off into the weeds.
 110 // (gcc explicitly supports the union trick.)  Other compilers may vary.
 111 // In particular, not all compilers do a good job with the memcpy.
 112 template<typename T, typename U>
 113 inline T IntegerTypes::cast_floating_point(U x) {
 114   STATIC_ASSERT(sizeof(T) == sizeof(U));
 115   T result;
 116   memcpy(&result, &x, sizeof(x));
 117   return result;
 118 }
 119 
 120 //////////////////////////////////////////////////////////////////////////////
 121 // cast<T>(x)
 122 //
 123 // Cast<T, U, same_size, to_category, from_category>
 124 
 125 // Give an informative error if the sizes differ.
 126 template<typename T, typename U,
 127          IntegerTypes::Category to_category,
 128          IntegerTypes::Category from_category>
 129 struct IntegerTypes::Cast<T, U, false, to_category, from_category>






 130   VALUE_OBJ_CLASS_SPEC
 131 {
 132   STATIC_ASSERT(sizeof(T) == sizeof(U));












 133 };
 134 
 135 #define DEFINE_INTEGER_TYPES_CAST(To, From, Convert)    \
 136   template<typename T, typename U>                      \
 137   struct IntegerTypes::Cast<T, U, true,                 \
 138                             IntegerTypes::To,           \
 139                             IntegerTypes::From>         \
 140     VALUE_OBJ_CLASS_SPEC                                \
 141   {                                                     \
 142     T operator()(U x) const { return Convert<T>(x); }   \
 143   };
 144 
 145 DEFINE_INTEGER_TYPES_CAST(INTEGRAL, INTEGRAL, cast_integral)
 146 DEFINE_INTEGER_TYPES_CAST(ENUM,     INTEGRAL, cast_integral)
 147 DEFINE_INTEGER_TYPES_CAST(INTEGRAL, ENUM,     cast_integral)
 148 DEFINE_INTEGER_TYPES_CAST(FLOAT,    INTEGRAL, cast_floating_point)
 149 DEFINE_INTEGER_TYPES_CAST(INTEGRAL, FLOAT,    cast_floating_point)
 150 DEFINE_INTEGER_TYPES_CAST(POINTER,  INTEGRAL, reinterpret_cast)
 151 DEFINE_INTEGER_TYPES_CAST(INTEGRAL, POINTER,  reinterpret_cast)
 152 
 153 #undef DEFINE_INTEGER_TYPES_CAST


















 154 
 155 template<typename T, typename U>
 156 inline T IntegerTypes::cast(U x) {
 157   return Cast<T, U>()(x);
 158 }
 159 
 160 #endif // SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP


   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP
  26 #define SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP
  27 
  28 #include "memory/allocation.hpp"

  29 #include "metaprogramming/enableIf.hpp"
  30 #include "metaprogramming/integralConstant.hpp"
  31 #include "metaprogramming/isFloatingPoint.hpp"


  32 #include "metaprogramming/isIntegral.hpp"
  33 #include "metaprogramming/isRegisteredEnum.hpp"
  34 #include "utilities/debug.hpp"
  35 
  36 class IntegerTypes : public AllStatic {
  37 public:
  38   // Return a value of type T with the same representation as x.
  39   //
  40   // T and U must be of the same size.
  41   //
  42   // At least one of T or U must be an integral type.  The other must
  43   // be an integral, floating point, or pointer type.
  44   template<typename T, typename U> static T cast(U x);
  45 
  46   // Support thin wrappers over primitive types.
  47   // If derived from TrueType, provides representational conversion
  48   // from T to some other type.  When true, must provide
  49   // - Value: typedef for T.
  50   // - Decayed: typedef for decayed type.
  51   // - static Decayed decay(T x): return value of type Decayed with
  52   //   the same representation as x.
  53   // - static T recover(Decayed x): return a value of type T with the
  54   //   same representation as x.
  55   template<typename T> struct Translate : public FalseType {};
  56 








  57 private:
  58 


  59   template<typename T,
  60            typename U,
  61            bool same_size = sizeof(T) == sizeof(U),
  62            typename Enable = void>

  63   struct Cast;
  64 
  65   template<typename T, typename U> static T cast_using_union(U x);

  66 };
  67 
  68 // Return an object of type T with the same value representation as x.
  69 //
  70 // T and U must be of the same size.  It is expected that one of T and
  71 // U is an integral type, and the other is an integral type, a
  72 // (registered) enum type, or a floating point type
  73 //
  74 // This implementation uses the "union trick", which seems to be the
  75 // best of a bad set of options.  Though technically undefined
  76 // behavior, it is widely and well supported, producing good code.  In
  77 // some cases, such as gcc, that support is explicitly documented.
  78 //
  79 // Using memcpy is the correct method, but some compilers produce
  80 // wretched code for that method, even at maximal optimization levels.
  81 //
  82 // Using static_cast is only possible for integral and enum types, not
  83 // for floating point types.  And for integral and enum conversions,
  84 // static_cast has unspecified or implementation-defined behavior for
  85 // some cases.  C++11 <type_traits> can be used to avoid most or all
  86 // of those unspecified or implementation-defined issues, though that
  87 // may require multi-step conversions.
  88 //
  89 // Using reinterpret_cast of references has undefined behavior for
  90 // many cases, and there is much less empirical basis for its use, as
  91 // compared to the union trick.







  92 template<typename T, typename U>
  93 inline T IntegerTypes::cast_using_union(U x) {
  94   STATIC_ASSERT(sizeof(T) == sizeof(U));
  95   union { T t; U u; };
  96   u = x;
  97   return t;
  98 }
  99 
 100 //////////////////////////////////////////////////////////////////////////////
 101 // cast<T>(x)
 102 //
 103 // Cast<T, U, same_size, Enable>
 104 
 105 // Give an informative error if the sizes differ.
 106 template<typename T, typename U>
 107 struct IntegerTypes::Cast<T, U, false> VALUE_OBJ_CLASS_SPEC {
 108   STATIC_ASSERT(sizeof(T) == sizeof(U));
 109 };
 110 
 111 // Conversion between integral types.
 112 template<typename T, typename U>
 113 struct IntegerTypes::Cast<
 114   T, U, true,
 115   typename EnableIf<IsIntegral<T>::value && IsIntegral<U>::value>::type>
 116   VALUE_OBJ_CLASS_SPEC
 117 {
 118   T operator()(U x) const { return cast_using_union<T>(x); }
 119 };
 120 
 121 // Convert an enum or floating point value to an integer value.
 122 template<typename T, typename U>
 123 struct IntegerTypes::Cast<
 124   T, U, true,
 125   typename EnableIf<IsIntegral<T>::value &&
 126                     (IsRegisteredEnum<U>::value ||
 127                      IsFloatingPoint<U>::value)>::type>
 128   VALUE_OBJ_CLASS_SPEC
 129 {
 130   T operator()(U x) const { return cast_using_union<T>(x); }
 131 };
 132 
 133 // Convert an integer to an enum or floating point value.
 134 template<typename T, typename U>
 135 struct IntegerTypes::Cast<
 136   T, U, true,
 137   typename EnableIf<IsIntegral<U>::value &&
 138                     (IsRegisteredEnum<T>::value ||
 139                      IsFloatingPoint<T>::value)>::type>
 140   VALUE_OBJ_CLASS_SPEC
 141 {
 142   T operator()(U x) const { return cast_using_union<T>(x); }
 143 };






 144 
 145 // Convert a pointer to an integral value.
 146 template<typename T, typename U>
 147 struct IntegerTypes::Cast<
 148   T, U*, true,
 149   typename EnableIf<IsIntegral<T>::value>::type>
 150   VALUE_OBJ_CLASS_SPEC
 151 {
 152   T operator()(U* x) const { return reinterpret_cast<T>(x); }
 153 };
 154 
 155 // Convert an integral value to a pointer.
 156 template<typename T, typename U>
 157 struct IntegerTypes::Cast<
 158   T*, U, true,
 159   typename EnableIf<IsIntegral<U>::value>::type>
 160   VALUE_OBJ_CLASS_SPEC
 161 {
 162   T* operator()(U x) const { return reinterpret_cast<T*>(x); }
 163 };
 164 
 165 template<typename T, typename U>
 166 inline T IntegerTypes::cast(U x) {
 167   return Cast<T, U>()(x);
 168 }
 169 
 170 #endif // SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP
< prev index next >