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_PRIMITIVECONVERSIONS_HPP 26#define SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_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 36class PrimitiveConversions : public AllStatic { 37public: 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 57private: 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. 92template<typename T, typename U> 93inline T PrimitiveConversions::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. 106template<typename T, typename U> 107struct PrimitiveConversions::Cast<T, U, false> VALUE_OBJ_CLASS_SPEC { 108 STATIC_ASSERT(sizeof(T) == sizeof(U)); 109}; 110 111// Conversion between integral types. 112template<typename T, typename U> 113struct PrimitiveConversions::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. 122template<typename T, typename U> 123struct PrimitiveConversions::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. 134template<typename T, typename U> 135struct PrimitiveConversions::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. 146template<typename T, typename U> 147struct PrimitiveConversions::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. 156template<typename T, typename U> 157struct PrimitiveConversions::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 165template<typename T, typename U> 166inline T PrimitiveConversions::cast(U x) { 167 return Cast<T, U>()(x); 168} 169 170#endif // SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP 171