[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-hotspot-dev
Subject:    Re: PATCH: using mixed types in MIN2/MAX2 functions
From:       Kim Barrett <kim.barrett () oracle ! com>
Date:       2014-06-20 18:03:32
Message-ID: F420349B-19EC-46EC-8E18-486D0D8B99AD () oracle ! com
[Download RAW message or body]

On Jun 19, 2014, at 9:06 AM, Dan Horák <dan@danny.cz> wrote:
> 
> On Thu, 19 Jun 2014 14:55:52 +0200
> Bengt Rutisson <bengt.rutisson@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); }

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic