1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   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/decay.hpp"
  31 #include "metaprogramming/integralConstant.hpp"
  32 #include "metaprogramming/isFloatingPoint.hpp"
  33 #include "metaprogramming/isPointer.hpp"
  34 #include "metaprogramming/isSigned.hpp"
  35 #include "metaprogramming/isIntegral.hpp"
  36 
  37 class IntegerTypes : public AllStatic {
  38 public:
  39   // Metafunction returning a canonical type of the same size and signed as T.
  40   // T must be an integral type. The canonical types are guaranteed to be
  41   // the [u]intN_t types from stdint.h
  42   template<typename T> struct Canonical;
  43 
  44   // Metafunction returning the canonical signed integral type of the
  45   // given size.
  46   template<size_t byte_size> struct SignedTypeOfSize;
  47 
  48   // Metafunction returning the canonical unsigned integral type of
  49   // the given size.
  50   template<size_t byte_size> struct UnsignedTypeOfSize;
  51 
  52   // Metafunction returning the canonical signed integral type of the
  53   // same size as T.  T must be an integral, floating point, or
  54   // pointer type.
  55   template<typename T> struct Signed;
  56 
  57   // Metafunction returning the canonical unsigned integral type of
  58   // the same size as T.  T must be an integral, floating point, or
  59   // pointer type.
  60   template<typename T> struct Unsigned;
  61 
  62   // Return a signed integral value with the same representation as x.
  63   // T must be an integral, floating point, or pointer type.
  64   // If T is a signed type, then x == cast_to_signed(x).
  65   template<typename T>
  66   static typename Signed<T>::type cast_to_signed(T x);
  67 
  68   // Return an unsigned integral value with the same representation as x.
  69   // T must be an integral, floating point, or pointer type.
  70   // If T is an unsigned type, then x == cast_to_unsigned(x).
  71   template<typename T>
  72   static typename Unsigned<T>::type cast_to_unsigned(T x);
  73 
  74   // Return a value with the same representation as x.
  75   // T must be an integral, floating point, or pointer type.
  76   // U must be an integral type.  T and U must be of the same size.
  77   // If T and U are both signed or both unsigned integral types, then
  78   // x == cast<T>(x).
  79   template<typename T, typename U>
  80   static T cast(U x);
  81 
  82 private:
  83   template<typename T, bool is_signed = IsSigned<T>::value>
  84   struct CanonicalImpl;
  85 
  86   template<typename T, bool is_pointer = IsPointer<T>::value, bool is_float = IsFloatingPoint<T>::value>
  87   struct TypeForSize;
  88 
  89   template<typename T, typename U, bool from_pointer = IsPointer<U>::value, bool from_float = IsFloatingPoint<U>::value>
  90   struct CastTo;
  91 
  92   template<typename T,
  93            typename U,
  94            bool same_size = sizeof(T) == sizeof(U),
  95            bool to_pointer = IsPointer<T>::value,
  96            bool to_float = IsFloatingPoint<T>::value>
  97   struct Cast;
  98 
  99   template<typename T, typename U> static T cast_integral(U x);
 100   template<typename T, typename U> static T cast_floating_point(U x);
 101 };
 102 
 103 // Convert between different integral types of the same size.
 104 // See C++03 3.10/15 for discussion of reinterpret_cast to a reference
 105 // as a means for converting integral types while keeping the representation.
 106 template<typename T, typename U>
 107 inline T IntegerTypes::cast_integral(U x) {
 108   STATIC_ASSERT(sizeof(T) == sizeof(U));
 109   return reinterpret_cast<T&>(x);
 110 }
 111 
 112 // Convert between an integral type and a floating point type of the
 113 // same size.  The only truly correct way to do this is with memcpy.
 114 // Both the union trick and type punning via casts are undefined
 115 // behavior. gcc generates exactly the same code for all three methods,
 116 // except where the UB of type punning causes it to go off into the weeds.
 117 // (gcc explicitly supports the union trick.)  Other compilers may vary.
 118 // In particular, not all compilers do a good job with the memcpy.
 119 template<typename T, typename U>
 120 inline T IntegerTypes::cast_floating_point(U x) {
 121   STATIC_ASSERT(sizeof(T) == sizeof(U));
 122   T result;
 123   memcpy(&result, &x, sizeof(x));
 124   return result;
 125 }
 126 
 127 //////////////////////////////////////////////////////////////////////////////
 128 // SignedTypeOfSize<size_t> and UnsignedTypeOfSize<size_t>
 129 
 130 #define DEFINE_CANONICAL_SIGNED_TYPE(T)                                 \
 131   template<>                                                            \
 132   struct IntegerTypes::SignedTypeOfSize<sizeof(T)> : public AllStatic { \
 133     typedef T type;                                                     \
 134   };
 135 
 136 #define DEFINE_CANONICAL_UNSIGNED_TYPE(T)                               \
 137   template<>                                                            \
 138   struct IntegerTypes::UnsignedTypeOfSize<sizeof(T)> : public AllStatic { \
 139     typedef T type;                                                     \
 140   };
 141 
 142 #define DEFINE_INTEGER_TYPES_OF_SIZE(NBITS)            \
 143   DEFINE_CANONICAL_SIGNED_TYPE(int ## NBITS ## _t)     \
 144   DEFINE_CANONICAL_UNSIGNED_TYPE(uint ## NBITS ## _t)
 145 
 146 DEFINE_INTEGER_TYPES_OF_SIZE(8)
 147 DEFINE_INTEGER_TYPES_OF_SIZE(16)
 148 DEFINE_INTEGER_TYPES_OF_SIZE(32)
 149 DEFINE_INTEGER_TYPES_OF_SIZE(64)
 150 
 151 #undef DEFINE_INTEGER_TYPES_OF_SIZE
 152 #undef DEFINE_CANONICAL_SIGNED_TYPE
 153 #undef DEFINE_CANONICAL_UNSIGNED_TYPE
 154 
 155 //////////////////////////////////////////////////////////////////////////////
 156 // Canonical<T>
 157 
 158 template<typename T>
 159 struct IntegerTypes::CanonicalImpl<T, true>
 160   : public SignedTypeOfSize<sizeof(T)>
 161 { };
 162 
 163 template<typename T>
 164 struct IntegerTypes::CanonicalImpl<T, false>
 165   : public UnsignedTypeOfSize<sizeof(T)>
 166 { };
 167 
 168 template<typename T>
 169 struct IntegerTypes::Canonical : public CanonicalImpl<T> {
 170   STATIC_ASSERT((IsIntegral<T>::value));
 171 };
 172 
 173 //////////////////////////////////////////////////////////////////////////////
 174 // Signed<T> and Unsigned<T>
 175 
 176 // For other types, use the canonical type, ensuring T is integral.
 177 template<typename T>
 178 struct IntegerTypes::TypeForSize<T, false, false> : public Canonical<T> { };
 179 
 180 // For floating point types, use the type.
 181 template<typename T>
 182 struct IntegerTypes::TypeForSize<T, false, true> : public AllStatic {
 183   typedef T type;
 184 };
 185 
 186 // For pointer types, use void*.
 187 template<typename T>
 188 struct IntegerTypes::TypeForSize<T, true, false> : public AllStatic {
 189   typedef void* type;
 190 };
 191 
 192 template<typename T>
 193 struct IntegerTypes::Signed
 194   : public SignedTypeOfSize<sizeof(typename TypeForSize<T>::type)>
 195 { };
 196 
 197 template<typename T>
 198 struct IntegerTypes::Unsigned
 199   : public UnsignedTypeOfSize<sizeof(typename TypeForSize<T>::type)>
 200 { };
 201 
 202 //////////////////////////////////////////////////////////////////////////////
 203 // cast<T>(x)
 204 //
 205 // Cast from an integral type to an integral, floating point, or pointer type.
 206 // Cast<T, U, same_size, to_pointer, to_float>
 207 
 208 // Cast integral value to some different type of integral value.
 209 template<typename T, typename U>
 210 struct IntegerTypes::Cast<T, U, true, false, false> VALUE_OBJ_CLASS_SPEC {
 211   T operator()(U x) const {
 212     // Canonicalization verifies T is integral.
 213     typedef typename Canonical<T>::type canonical_type;
 214     return static_cast<T>(cast_integral<canonical_type>(x));
 215   }
 216 };
 217 
 218 // Cast integral value to floating point.
 219 template<typename T, typename U>
 220 struct IntegerTypes::Cast<T, U, true, false, true> VALUE_OBJ_CLASS_SPEC {
 221   T operator()(U x) const { return cast_floating_point<T>(x); }
 222 };
 223 
 224 // Cast integral value to pointer.
 225 template<typename T, typename U>
 226 struct IntegerTypes::Cast<T, U, true, true, false> VALUE_OBJ_CLASS_SPEC {
 227   T operator()(U x) const { return reinterpret_cast<T>(x); }
 228 };
 229 
 230 // Same integral type is identity conversion.
 231 template<typename T>
 232 struct IntegerTypes::Cast<T, T, true, false, false> VALUE_OBJ_CLASS_SPEC {
 233   T operator()(T x) const { return x; }
 234 };
 235 
 236 // Give an informative error if the sizes differ.
 237 template<typename T, typename U, bool to_pointer, bool to_float>
 238 struct IntegerTypes::Cast<T, U, false, to_pointer, to_float> VALUE_OBJ_CLASS_SPEC {
 239   STATIC_ASSERT(sizeof(T) == sizeof(U));
 240 };
 241 
 242 template<typename T, typename U>
 243 inline T IntegerTypes::cast(U x) {
 244   // Canonicalization verifies U is integral.
 245   typedef typename Canonical<U>::type parameter_type;
 246   return Cast<T, parameter_type>()(static_cast<parameter_type>(x));
 247 }
 248 
 249 //////////////////////////////////////////////////////////////////////////////
 250 // cast_to_signed(x)
 251 // cast_to_unsigned(x)
 252 //
 253 // Cast from an integral, floating point, or pointer type to an integral type.
 254 
 255 // Cast integral to different integral.
 256 template<typename T, typename U>
 257 struct IntegerTypes::CastTo<T, U, false, false> VALUE_OBJ_CLASS_SPEC {
 258   T operator()(U x) const { return cast_integral<T>(x); }
 259 };
 260 
 261 // Cast floating point to integral value.
 262 template<typename T, typename U>
 263 struct IntegerTypes::CastTo<T, U, false, true> VALUE_OBJ_CLASS_SPEC {
 264   T operator()(U x) const { return cast_floating_point<T>(x); }
 265 };
 266 
 267 // Cast pointer to integral value.
 268 template<typename T, typename U>
 269 struct IntegerTypes::CastTo<T, U, true, false> VALUE_OBJ_CLASS_SPEC {
 270   T operator()(U x) const { return reinterpret_cast<T>(x); }
 271 };
 272 
 273 // Identity conversion
 274 template<typename T>
 275 struct IntegerTypes::CastTo<T, T, false, false> VALUE_OBJ_CLASS_SPEC {
 276   T operator()(T x) const { return x; }
 277 };
 278 
 279 template<typename T>
 280 inline typename IntegerTypes::Signed<T>::type
 281 IntegerTypes::cast_to_signed(T x) {
 282   typedef typename Signed<T>::type result_type;
 283   return CastTo<result_type, T>()(x);
 284 }
 285 
 286 template<typename T>
 287 inline typename IntegerTypes::Unsigned<T>::type
 288 IntegerTypes::cast_to_unsigned(T x) {
 289   typedef typename Unsigned<T>::type result_type;
 290   return CastTo<result_type, T>()(x);
 291 }
 292 
 293 #endif // SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP