| 1 | /* |
| 2 | * Copyright (c) 2017, 2019, 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_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP |
| 26 | #define SHARE_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 | |
| 36 | class PrimitiveConversions : 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 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. |
| 106 | template<typename T, typename U> |
| 107 | struct PrimitiveConversions::Cast<T, U, false> { |
| 108 | STATIC_ASSERT(sizeof(T) == sizeof(U)); |
| 109 | }; |
| 110 | |
| 111 | // Conversion between integral types. |
| 112 | template<typename T, typename U> |
| 113 | struct PrimitiveConversions::Cast< |
| 114 | T, U, true, |
| 115 | typename EnableIf<IsIntegral<T>::value && IsIntegral<U>::value>::type> |
| 116 | { |
| 117 | T operator()(U x) const { return cast_using_union<T>(x); } |
| 118 | }; |
| 119 | |
| 120 | // Convert an enum or floating point value to an integer value. |
| 121 | template<typename T, typename U> |
| 122 | struct PrimitiveConversions::Cast< |
| 123 | T, U, true, |
| 124 | typename EnableIf<IsIntegral<T>::value && |
| 125 | (IsRegisteredEnum<U>::value || |
| 126 | IsFloatingPoint<U>::value)>::type> |
| 127 | { |
| 128 | T operator()(U x) const { return cast_using_union<T>(x); } |
| 129 | }; |
| 130 | |
| 131 | // Convert an integer to an enum or floating point value. |
| 132 | template<typename T, typename U> |
| 133 | struct PrimitiveConversions::Cast< |
| 134 | T, U, true, |
| 135 | typename EnableIf<IsIntegral<U>::value && |
| 136 | (IsRegisteredEnum<T>::value || |
| 137 | IsFloatingPoint<T>::value)>::type> |
| 138 | { |
| 139 | T operator()(U x) const { return cast_using_union<T>(x); } |
| 140 | }; |
| 141 | |
| 142 | // Convert a pointer to an integral value. |
| 143 | template<typename T, typename U> |
| 144 | struct PrimitiveConversions::Cast< |
| 145 | T, U*, true, |
| 146 | typename EnableIf<IsIntegral<T>::value>::type> |
| 147 | { |
| 148 | T operator()(U* x) const { return reinterpret_cast<T>(x); } |
| 149 | }; |
| 150 | |
| 151 | // Convert an integral value to a pointer. |
| 152 | template<typename T, typename U> |
| 153 | struct PrimitiveConversions::Cast< |
| 154 | T*, U, true, |
| 155 | typename EnableIf<IsIntegral<U>::value>::type> |
| 156 | { |
| 157 | T* operator()(U x) const { return reinterpret_cast<T*>(x); } |
| 158 | }; |
| 159 | |
| 160 | template<typename T, typename U> |
| 161 | inline T PrimitiveConversions::cast(U x) { |
| 162 | return Cast<T, U>()(x); |
| 163 | } |
| 164 | |
| 165 | // jfloat and jdouble translation to integral types |
| 166 | |
| 167 | template<> |
| 168 | struct PrimitiveConversions::Translate<jdouble> : public TrueType { |
| 169 | typedef double Value; |
| 170 | typedef int64_t Decayed; |
| 171 | |
| 172 | static Decayed decay(Value x) { return PrimitiveConversions::cast<Decayed>(x); } |
| 173 | static Value recover(Decayed x) { return PrimitiveConversions::cast<Value>(x); } |
| 174 | }; |
| 175 | |
| 176 | template<> |
| 177 | struct PrimitiveConversions::Translate<jfloat> : public TrueType { |
| 178 | typedef float Value; |
| 179 | typedef int32_t Decayed; |
| 180 | |
| 181 | static Decayed decay(Value x) { return PrimitiveConversions::cast<Decayed>(x); } |
| 182 | static Value recover(Decayed x) { return PrimitiveConversions::cast<Value>(x); } |
| 183 | }; |
| 184 | |
| 185 | #endif // SHARE_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP |
| 186 | |