/* * 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/enableIf.hpp" #include "metaprogramming/integralConstant.hpp" #include "metaprogramming/isFloatingPoint.hpp" #include "metaprogramming/isPointer.hpp" #include "metaprogramming/isRegisteredEnum.hpp" #include "metaprogramming/isIntegral.hpp" class IntegerTypes : public AllStatic { public: // Return a value of type T with the same representation as x. // // T and U must be of the same size. // // At least one of T or U must be an integral type. The other must // be an integral, floating point, or pointer type. template static T cast(U x); // Support thin wrappers over primitive types. // If derived from TrueType, provides representational conversion // from T to some other type. When true, must provide // - Value: typedef for T. // - Decayed: typedef for decayed type. // - static Decayed decay(T x): return value of type Decayed with // the same representation as x. // - static T recover(Decayed x): return a value of type T with the // same representation as x. template struct Translate : public FalseType {}; // Value categories. For internal use, but needs to be public. enum Category { INTEGRAL, ENUM, FLOAT, POINTER }; private: template struct GetCategory; template::value, Category from_category = GetCategory::value> struct Cast; template static T cast_integral(U x); template static T cast_floating_point(U x); }; #define DEFINE_GET_CATEGORY(Predicate, Value) \ template \ struct IntegerTypes::GetCategory< \ T, \ typename EnableIf::value>::type> \ : IntegralConstant \ {}; DEFINE_GET_CATEGORY(IsIntegral, INTEGRAL) DEFINE_GET_CATEGORY(IsRegisteredEnum, ENUM) DEFINE_GET_CATEGORY(IsFloatingPoint, FLOAT) DEFINE_GET_CATEGORY(IsPointer, POINTER) #undef DEFINE_GET_CATEGORY // 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; } ////////////////////////////////////////////////////////////////////////////// // cast(x) // // Cast // Give an informative error if the sizes differ. template struct IntegerTypes::Cast VALUE_OBJ_CLASS_SPEC { STATIC_ASSERT(sizeof(T) == sizeof(U)); }; #define DEFINE_INTEGER_TYPES_CAST(To, From, Convert) \ template \ struct IntegerTypes::Cast \ VALUE_OBJ_CLASS_SPEC \ { \ T operator()(U x) const { return Convert(x); } \ }; DEFINE_INTEGER_TYPES_CAST(INTEGRAL, INTEGRAL, cast_integral) DEFINE_INTEGER_TYPES_CAST(ENUM, INTEGRAL, cast_integral) DEFINE_INTEGER_TYPES_CAST(INTEGRAL, ENUM, cast_integral) DEFINE_INTEGER_TYPES_CAST(FLOAT, INTEGRAL, cast_floating_point) DEFINE_INTEGER_TYPES_CAST(INTEGRAL, FLOAT, cast_floating_point) DEFINE_INTEGER_TYPES_CAST(POINTER, INTEGRAL, reinterpret_cast) DEFINE_INTEGER_TYPES_CAST(INTEGRAL, POINTER, reinterpret_cast) #undef DEFINE_INTEGER_TYPES_CAST template inline T IntegerTypes::cast(U x) { return Cast()(x); } #endif // SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP