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