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