Thursday 12 April 2012

c++11 reference implementation for std::min and std::max

Prepare to have your mind boggled!

This is a reference implementation for std::min and std::max, using c++11 features


namespace detail
{

template <class T, bool make_const, bool make_volatile>
struct union_cv_helper;

template <class T>
struct union_cv_helper<T, false, false>
{
    typedef T type;
};

template <class T>
struct union_cv_helper<T, false, true>
{
    typedef volatile T type;
};

template <class T>
struct union_cv_helper<T, true, false>
{
    typedef const T type;
};

template <class T>
struct union_cv_helper<T, true, true>
{
    typedef const volatile T type;
};

}  // detail

template <class T, class U>
struct union_cv
{
    static const bool make_const = std::tr1::is_const<T>::value || std::tr1::is_const<U>::value;
    static const bool make_volatile = std::tr1::is_volatile<T>::value || std::tr1::is_volatile<U>::value;
    typedef typename std::tr1::remove_cv<T>::type Tr;
    typedef typename std::tr1::remove_cv<U>::type Ur;
    typedef typename detail::union_cv_helper<Tr, make_const, make_volatile>::type type;
};

template <class T, class U>
struct promote
{
    static T t;
    static U u;
    static bool b;
    typedef typename std::tr1::remove_cv<decltype(b ? t : u)>::type type;
};

namespace detail
{

template <class T, class Tr, class U, class Ur>
struct min_max_return_helper
{
    typedef typename promote<T&, U&>::type type;
};

template <class T, class Tr, class U>
struct min_max_return_helper<T, Tr, U, Tr>
{
    typedef typename union_cv<T, U>::type& type;
};

template <class T, T t, class U, U u>
struct safe_less_equal
{
    static const bool Tsigned = std::tr1::is_signed<T>::value;
    static const bool Usigned = std::tr1::is_signed<U>::value;
    static const bool Tneg = Tsigned && t < T(0);
    static const bool Uneg = Usigned && u < U(0);
    static const bool value = Tneg == Uneg ? t <= u : Tneg;
};

template <class T>
struct int_min
{
    static const T value = std::tr1::is_signed<T>::value ? T(T(1) << std::numeric_limits<T>::digits) : T(0);
};

template <class T>
struct int_max
{
    static const T value = T(~int_min<T>::value);
};

template <class T, class U, bool = std::tr1::is_integral<T>::value && std::tr1::is_integral<U>::value>
struct safe_compare_imp
{
    typedef typename promote<T, U>::type R;
    static const R Rmin = int_min<R>::value;
    static const R Rmax = int_max<R>::value;

    static const T Tmin = int_min<T>::value;
    static const T Tmax = int_max<T>::value;

    static const U Umin = int_min<U>::value;
    static const U Umax = int_max<U>::value;

    static const bool value = safe_less_equal<R, Rmin, T, Tmin>::value &&
                              safe_less_equal<R, Rmin, U, Umin>::value &&
                              safe_less_equal<T, Tmax, R, Rmax>::value &&
                              safe_less_equal<U, Umax, R, Rmax>::value;
};

template <class T, class U>
struct safe_compare_imp<T, U, false>
{
    static const bool value = true;
};

template <class T>
struct safe_compare_imp<T, T, true>
{
    static const bool value = true;
};

template <class T>
struct safe_compare_imp<T, T, false>
{
    static const bool value = true;
};

template <class T, class U>
struct safe_compare
{
private:
    typedef typename std::tr1::remove_cv<typename std::tr1::remove_reference<T>::type>::type Tr;
    typedef typename std::tr1::remove_cv<typename std::tr1::remove_reference<U>::type>::type Ur;
public:
    static const bool value = detail::safe_compare_imp<Tr, Ur>::value;
};

}  // detail

template <class T, class U, bool = detail::safe_compare<T, U>::value>
struct min_max_return {};

template <class T, class U>
struct min_max_return<T&&, U&&, true>
{
    typedef typename promote<T&&, U&&>::type type;
};

template <class T, class U>
struct min_max_return<T&&, U&, true>
{
    typedef typename promote<T&&, U&>::type type;
};

template <class T, class U>
struct min_max_return<T&, U&&, true>
{
    typedef typename promote<T&, U&&>::type type;
};

template <class T, class U>
struct min_max_return<T&, U&, true>
{
private:
    typedef typename std::tr1::remove_cv<T>::type Tr;
    typedef typename std::tr1::remove_cv<U>::type Ur;
public:
    typedef typename detail::min_max_return_helper<T, Tr, U, Ur>::type type;
};

template <class T, class U>
inline
typename min_max_return<T&&, U&&>::type
min(T&& a, U&& b)
{
    if (b < a)
        return std::forward<U>(b);
    return std::forward<T>(a);
}

template <class T, class U, class Compare>
inline
typename min_max_return<T&&, U&&>::type
min(T&& a, U&& b, Compare comp)
{
    if (comp(b, a))
        return std::forward<U>(b);
    return std::forward<T>(a);
}

template <class T, class U>
inline
typename min_max_return<T&&, U&&>::type
max(T&& a, U&& b)
{
    if (a < b)
        return std::forward<U>(b);
    return std::forward<T>(a);
}

template <class T, class U, class Compare>
inline
typename min_max_return<T&&, U&&>::type
max(T&& a, U&& b, Compare comp)
{
    if (comp(a, b))
        return std::forward<U>(b);
    return std::forward<T>(a);
}

No comments:

Post a Comment