/* * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #ifndef SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP #define SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP #include "memory/allocation.hpp" #include "utilities/debug.hpp" #include "metaprogramming/decay.hpp" #include "metaprogramming/integralConstant.hpp" #include "metaprogramming/isFloatingPoint.hpp" #include "metaprogramming/isPointer.hpp" #include "metaprogramming/isSigned.hpp" #include "metaprogramming/isIntegral.hpp" class IntegerTypes : public AllStatic { public: // Metafunction returning a canonical type of the same size and signed as T. // T must be an integral type. The canonical types are guaranteed to be // the [u]intN_t types from stdint.h template struct Canonical; // Metafunction returning the canonical signed integral type of the // given size. template struct SignedTypeOfSize; // Metafunction returning the canonical unsigned integral type of // the given size. template struct UnsignedTypeOfSize; // Metafunction returning the canonical signed integral type of the // same size as T. T must be an integral, floating point, or // pointer type. template struct Signed; // Metafunction returning the canonical unsigned integral type of // the same size as T. T must be an integral, floating point, or // pointer type. template struct Unsigned; // Return a signed integral value with the same representation as x. // T must be an integral, floating point, or pointer type. // If T is a signed type, then x == cast_to_signed(x). template static typename Signed::type cast_to_signed(T x); // Return an unsigned integral value with the same representation as x. // T must be an integral, floating point, or pointer type. // If T is an unsigned type, then x == cast_to_unsigned(x). template static typename Unsigned::type cast_to_unsigned(T x); // Return a value with the same representation as x. // T must be an integral, floating point, or pointer type. // U must be an integral type. T and U must be of the same size. // If T and U are both signed or both unsigned integral types, then // x == cast(x). template static T cast(U x); private: template::value> struct CanonicalImpl; template::value, bool is_float = IsFloatingPoint::value> struct TypeForSize; template::value, bool from_float = IsFloatingPoint::value> struct CastTo; template::value, bool to_float = IsFloatingPoint::value> struct Cast; template static T cast_integral(U x); template static T cast_floating_point(U x); }; // Convert between different integral types of the same size. // See C++03 3.10/15 for discussion of reinterpret_cast to a reference // as a means for converting integral types while keeping the representation. template inline T IntegerTypes::cast_integral(U x) { STATIC_ASSERT(sizeof(T) == sizeof(U)); return reinterpret_cast(x); } // Convert between an integral type and a floating point type of the // same size. The only truly correct way to do this is with memcpy. // Both the union trick and type punning via casts are undefined // behavior. gcc generates exactly the same code for all three methods, // except where the UB of type punning causes it to go off into the weeds. // (gcc explicitly supports the union trick.) Other compilers may vary. // In particular, not all compilers do a good job with the memcpy. template inline T IntegerTypes::cast_floating_point(U x) { STATIC_ASSERT(sizeof(T) == sizeof(U)); T result; memcpy(&result, &x, sizeof(x)); return result; } ////////////////////////////////////////////////////////////////////////////// // SignedTypeOfSize and UnsignedTypeOfSize #define DEFINE_CANONICAL_SIGNED_TYPE(T) \ template<> \ struct IntegerTypes::SignedTypeOfSize : public AllStatic { \ typedef T type; \ }; #define DEFINE_CANONICAL_UNSIGNED_TYPE(T) \ template<> \ struct IntegerTypes::UnsignedTypeOfSize : public AllStatic { \ typedef T type; \ }; #define DEFINE_INTEGER_TYPES_OF_SIZE(NBITS) \ DEFINE_CANONICAL_SIGNED_TYPE(int ## NBITS ## _t) \ DEFINE_CANONICAL_UNSIGNED_TYPE(uint ## NBITS ## _t) DEFINE_INTEGER_TYPES_OF_SIZE(8) DEFINE_INTEGER_TYPES_OF_SIZE(16) DEFINE_INTEGER_TYPES_OF_SIZE(32) DEFINE_INTEGER_TYPES_OF_SIZE(64) #undef DEFINE_INTEGER_TYPES_OF_SIZE #undef DEFINE_CANONICAL_SIGNED_TYPE #undef DEFINE_CANONICAL_UNSIGNED_TYPE ////////////////////////////////////////////////////////////////////////////// // Canonical template struct IntegerTypes::CanonicalImpl : public SignedTypeOfSize { }; template struct IntegerTypes::CanonicalImpl : public UnsignedTypeOfSize { }; template struct IntegerTypes::Canonical : public CanonicalImpl { STATIC_ASSERT((IsIntegral::value)); }; ////////////////////////////////////////////////////////////////////////////// // Signed and Unsigned // For other types, use the canonical type, ensuring T is integral. template struct IntegerTypes::TypeForSize : public Canonical { }; // For floating point types, use the type. template struct IntegerTypes::TypeForSize : public AllStatic { typedef T type; }; // For pointer types, use void*. template struct IntegerTypes::TypeForSize : public AllStatic { typedef void* type; }; template struct IntegerTypes::Signed : public SignedTypeOfSize::type)> { }; template struct IntegerTypes::Unsigned : public UnsignedTypeOfSize::type)> { }; ////////////////////////////////////////////////////////////////////////////// // cast(x) // // Cast from an integral type to an integral, floating point, or pointer type. // Cast // Cast integral value to some different type of integral value. template struct IntegerTypes::Cast VALUE_OBJ_CLASS_SPEC { T operator()(U x) const { // Canonicalization verifies T is integral. typedef typename Canonical::type canonical_type; return static_cast(cast_integral(x)); } }; // Cast integral value to floating point. template struct IntegerTypes::Cast VALUE_OBJ_CLASS_SPEC { T operator()(U x) const { return cast_floating_point(x); } }; // Cast integral value to pointer. template struct IntegerTypes::Cast VALUE_OBJ_CLASS_SPEC { T operator()(U x) const { return (T)((void*)x); } }; // Same integral type is identity conversion. template struct IntegerTypes::Cast VALUE_OBJ_CLASS_SPEC { T operator()(T x) const { return x; } }; // Give an informative error if the sizes differ. template struct IntegerTypes::Cast VALUE_OBJ_CLASS_SPEC { STATIC_ASSERT(sizeof(T) == sizeof(U)); }; template inline T IntegerTypes::cast(U x) { // Canonicalization verifies U is integral. typedef typename Canonical::type parameter_type; return Cast()(static_cast(x)); } ////////////////////////////////////////////////////////////////////////////// // cast_to_signed(x) // cast_to_unsigned(x) // // Cast from an integral, floating point, or pointer type to an integral type. // Cast integral to different integral. template struct IntegerTypes::CastTo VALUE_OBJ_CLASS_SPEC { T operator()(U x) const { return cast_integral(x); } }; // Cast floating point to integral value. template struct IntegerTypes::CastTo VALUE_OBJ_CLASS_SPEC { T operator()(U x) const { return cast_floating_point(x); } }; // Cast pointer to integral value. template struct IntegerTypes::CastTo VALUE_OBJ_CLASS_SPEC { T operator()(U x) const { return reinterpret_cast(x); } }; // Identity conversion template struct IntegerTypes::CastTo VALUE_OBJ_CLASS_SPEC { T operator()(T x) const { return x; } }; template inline typename IntegerTypes::Signed::type IntegerTypes::cast_to_signed(T x) { typedef typename Signed::type result_type; return CastTo()(x); } template inline typename IntegerTypes::Unsigned::type IntegerTypes::cast_to_unsigned(T x) { typedef typename Unsigned::type result_type; return CastTo()(x); } #endif // SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP