PATCH: using mixed types in MIN2/MAX2 functions
Jesper Wilhelmsson
jesper.wilhelmsson at oracle.com
Mon Jul 28 21:56:39 UTC 2014
Hi Dan, Kim, and others,
Trying to get this discussion going again.
There isn't too much of non-trivial template usage in HotSpot today and I'm not
sure I think it's worth complicating the code to avoid a few type casts.
How do other people feel about the non-trivial template usage?
/Jesper
Kim Barrett skrev 20/6/14 20:03:
> On Jun 19, 2014, at 9:06 AM, Dan Horák <dan at danny.cz> wrote:
>>
>> On Thu, 19 Jun 2014 14:55:52 +0200
>> Bengt Rutisson <bengt.rutisson at oracle.com> wrote:
>>> Can you explain more in detail why it is not possible to specialize
>>> the MIN2 and MAX2 functions? You are probably correct, because when I
>>> read the comment in the code it says:
>>>
>>>
>>> // It is necessary to use templates here. Having normal overloaded
>>> // functions does not work because it is necessary to provide both 32-
>>> // and 64-bit overloaded functions, which does not work, and having
>>> // explicitly-typed versions of these routines (i.e., MAX2I, MAX2L)
>>> // will be even more error-prone than macros.
>>> template<class T> inline T MAX2(T a, T b) { return (a >
>>> b) ? a : b; }
>>>
>>>
>>> This kind of says what you also said. That it is not possible, but it
>>> does not really explain why.
>>>
>>> Can you explain why we can have definitions like:
>>>
>>> inline uint MAX2(uint a, size_t b)
>>> inline uint MAX2(size_t a, uint b)
>>
>> if I remember correctly from my previous experience, these 2 definition
>> conflict with the existing
>> inline uint MAX2(uint a, uint b)
>> on platforms where size_t == uint. But I might be wrong, the easiest we
>> can do, is to try add them. Or we could add the new definitions only
>> for s390 with #if defined(__s390__) && ! defined(__s390x__). Or maybe
>> there is another way to add them only when size_t != uint. A C++ expert
>> is required :-)
>
> This isn’t too difficult. The tests at the end should of course be turned into real test cases.
>
> Requires
>
> - <limits>
> - std::numeric_limits<T>::is_specialized
> - for specialized types
> - std::numeric_limits<T>::is_integer
> - std::numeric_limits<T>::is_signed
> - partial template specialization
> - SFINAE for function return types
>
> I have no idea whether all of our toolchains support all that. I’ve heard of some
> strange defects around numeric_limits with some (older) toolchains. For example,
> boost provides
> BOOST_NO_LIMIT - does not provide <limits>
> BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
> std::numeric_limits<T>::is_signed and similar are not available at compile-time.
> Neither of those seem to be applicable to any toolchain relevant to jdk code though.
>
> I also don't know how folks feel about non-trivial template usage.
>
> ———————
>
> #include <limits>
>
> // MIN2/MAX2(a, b) compare a and b and return the lesser/greater.
> //
> // a and b must either
> //
> // - be of the same type, in which case the result is of that type, or
> //
> // - both be of integer types with the same signed-ness, in which case the
> // result is the larger of those two types.
>
> template<typename T, typename U, bool T_Smaller = (sizeof(T) < sizeof(U))>
> struct MINMAX2_result_differ_choose { typedef U type; };
>
> template<typename T, typename U>
> struct MINMAX2_result_differ_choose<T, U, false> { typedef T type; };
>
> template<typename T, typename U,
> bool T_Integer = std::numeric_limits<T>::is_specialized,
> bool U_Integer = std::numeric_limits<U>::is_specialized>
> struct MINMAX2_result_differ { };
>
> template<typename T, typename U,
> bool T_Integer = std::numeric_limits<T>::is_integer,
> bool U_Integer = std::numeric_limits<U>::is_integer,
> bool SameSigned = (std::numeric_limits<T>::is_signed
> == std::numeric_limits<U>::is_signed)>
> struct MINMAX2_result_differ_aux { };
>
> template<typename T, typename U>
> struct MINMAX2_result_differ_aux<T, U, true, true, true>
> : public MINMAX2_result_differ_choose<T, U>
> { };
>
> template<typename T, typename U>
> struct MINMAX2_result_differ<T, U, true, true>
> : public MINMAX2_result_differ_aux<T, U>
> { };
>
> template<typename T, typename U>
> struct MINMAX2_result_type
> : public MINMAX2_result_differ<T, U>
> { };
>
> template<typename T>
> struct MINMAX2_result_type<T, T> {
> typedef T type;
> };
>
> template<typename T, typename U>
> inline typename MINMAX2_result_type<T, U>::type MAX2(T a, U b) {
> // note: if T & U are different integral types, terniary operator will
> // perform implicit promotion of the smaller to the larger.
> return a > b ? a : b;
> }
>
> template<typename T, typename U>
> inline typename MINMAX2_result_type<T, U>::type MIN2(T a, U b) {
> // note: if T & U are different integral types, terniary operator will
> // perform implicit promotion of the smaller to the larger.
> return a < b ? a : b;
> }
>
> // TESTS
>
> typedef unsigned int uint;
> typedef unsigned int uint_size_t;
> typedef unsigned long ulong_size_t;
>
> uint max_same1(uint a, uint_size_t b) { return MAX2(a, b); }
> uint max_same2(uint_size_t a, uint b) { return MAX2(a, b); }
>
> uint min_same1(uint a, uint_size_t b) { return MIN2(a, b); }
> uint min_same2(uint_size_t a, uint b) { return MIN2(a, b); }
>
> ulong_size_t max_diff1(uint a, ulong_size_t b) { return MAX2(a, b); }
> ulong_size_t max_diff2(ulong_size_t a, uint b) { return MAX2(a, b); }
>
> ulong_size_t min_diff1(uint a, ulong_size_t b) { return MIN2(a, b); }
> ulong_size_t min_diff2(ulong_size_t a, uint b) { return MIN2(a, b); }
>
> ulong_size_t max_ulong_size_t(ulong_size_t a, ulong_size_t b) {
> return MAX2(a, b);
> }
>
> uint_size_t max_uing_size_t(uint_size_t a, uint_size_t b) {
> return MAX2(a, b);
> }
>
> ulong_size_t min_ulong_size_t(ulong_size_t a, ulong_size_t b) {
> return MIN2(a, b);
> }
>
> uint_size_t min_uing_size_t(uint_size_t a, uint_size_t b) {
> return MIN2(a, b);
> }
>
> // these aren't supposed to compile
>
> // float max_float1(uint a, float b) { return MAX2(a, b); }
> // float max_float2(float a, uint b) { return MAX2(a, b); }
>
> // float min_float1(uint a, float b) { return MIN2(a, b); }
> // float min_float2(float a, uint b) { return MIN2(a, b); }
>
> // uint max_int1(uint a, int b) { return MAX2(a, b); }
> // uint max_int2(int a, uint b) { return MAX2(a, b); }
>
> // uint min_int1(uint a, int b) { return MIN2(a, b); }
> // uint min_int2(int a, uint b) { return MIN2(a, b); }
>
> // uint max_long1(uint a, long b) { return MAX2(a, b); }
> // uint max_long2(long a, uint b) { return MAX2(a, b); }
>
> // uint min_long1(uint a, long b) { return MIN2(a, b); }
> // uint min_long2(long a, uint b) { return MIN2(a, b); }
>
More information about the hotspot-dev
mailing list