Skip to content

Instantly share code, notes, and snippets.

@gyakoo
Forked from thomcc/min_max.hh
Created May 18, 2018 18:54
Show Gist options
  • Save gyakoo/96e6aeb9039b81c74b7a438db2c0aa37 to your computer and use it in GitHub Desktop.
Save gyakoo/96e6aeb9039b81c74b7a438db2c0aa37 to your computer and use it in GitHub Desktop.
C++11 variadic max, min, and minmax implementations.
#pragma once
#include <utility>
// varidic max, min, and minmax implementation (named maximum, minimum and min_max to avoid confusion)
// no support for custom comparators (mainly because i'm not sure how they should be specified)
namespace detail {
// max base case
template <class T>
constexpr T const &do_max(T const &v) {
return v;
}
// max inductive case
template <class T, class... Rest> // requires SameType<T, Rest...>
constexpr T const &do_max(T const &v0, T const &v1, Rest const &... rest) {
return do_max(v0 < v1 ? v1 : v0, rest...);
}
// min base case
template <class T>
constexpr T const &do_min(T const &v) {
return v;
}
// min variadic inductive case
template <class T, class... Rest> // requires SameType<T, Rest...>
constexpr T const &do_min(T const &v0, T const &v1, Rest const &...rest) {
return do_min(v0 < v1 ? v0 : v1, rest...);
}
// min_max base case
template <class T>
constexpr std::pair<T const&, T const&>
do_min_max(T const &cmin, T const &cmax) {
return { cmin, cmax };
}
// min_max inductive case
template <class T, class... Rest> // requires SameType<T, Rest...>
constexpr std::pair<T const &, T const &>
do_min_max(T const &cmin, T const &cmax, T const &next, Rest const &... rest) {
return do_min_max(
cmin < next ? cmin : next,
next < cmax ? cmax : next,
rest...
);
}
} // namespace detail
// public interface for minimum
template <class T, class ...Rest> // requires SameType<T, Rest...>
inline constexpr T const &
minimum(T const &first, Rest const &... rest) {
return detail::do_min(first, rest...);
}
// public interface for maximum
template <class T, class ...Rest> // requires SameType<T, Rest...>
inline constexpr T const &
maximum(T const &first, Rest const &... rest) {
return detail::do_max(first, rest...);
}
// public interface for min_max
template <class T, class ...Rest> // requires SameType<T, Rest...>
inline constexpr std::pair<T const &, T const &>
min_max(T const &first, Rest const &... rest) {
return detail::do_min_max(first, first, rest...);
}
// tests
namespace test_detail {
#define MIN_MAX_STATIC_TEST_CASE(FIRST, SECOND, ...) \
static_assert(min_max(__VA_ARGS__).first == FIRST, "bad min_max.first"); \
static_assert(min_max(__VA_ARGS__).second == SECOND, "bad min_max.second"); \
static_assert(minimum(__VA_ARGS__) == FIRST, "bad minimum"); \
static_assert(maximum(__VA_ARGS__) == SECOND, "bad maximum")
template <class T>
struct MinMaxTester {
MIN_MAX_STATIC_TEST_CASE(T{+1}, T{5}, T{1}, T{2}, T{3}, T{4}, T{5});
MIN_MAX_STATIC_TEST_CASE(T{+1}, T{5}, T{5}, T{4}, T{3}, T{2}, T{1});
MIN_MAX_STATIC_TEST_CASE(T{-1}, T{5}, T{5}, T{1}, T{5}, T{1}, T{2}, T{0}, T{-1}, T{1}, T{2}, T{2});
MIN_MAX_STATIC_TEST_CASE(T{20}, T{20}, T{20});
};
#undef MIN_MAX_STATIC_TEST_CASE
// type offering operator< but not operator>
struct NoGreater {
int v;
constexpr NoGreater(int n) : v(n) {}
constexpr bool operator<(NoGreater const &o) const { return v < o.v; }
constexpr bool operator==(NoGreater const &o) const { return v == o.v; } // for use with MIN_MAX_STATIC_TEST_CASE
};
typedef MinMaxTester<int> MinMaxTestInt;
typedef MinMaxTester<float> MinMaxTestFloat;
typedef MinMaxTester<NoGreater> MinMaxTestNoGreater;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment