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
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> {
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{
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.
121template<typename T, typename U>
122struct 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.
132template<typename T, typename U>
133struct 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.
143template<typename T, typename U>
144struct 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.
152template<typename T, typename U>
153struct 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
160template<typename T, typename U>
161inline T PrimitiveConversions::cast(U x) {
162 return Cast<T, U>()(x);
163}
164
165// jfloat and jdouble translation to integral types
166
167template<>
168struct 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
176template<>
177struct 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