| 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 |  | 
|---|