--- /dev/null 2017-03-07 11:44:12.271151064 +0100 +++ new/src/share/vm/metaprogramming/integerTypes.hpp 2017-07-27 17:46:47.227146559 +0200 @@ -0,0 +1,293 @@ +/* + * 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 reinterpret_cast(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