PATCH: using mixed types in MIN2/MAX2 functions
Kim Barrett
kim.barrett at oracle.com
Fri Jun 20 18:03:32 UTC 2014
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