fun: initializer_list min/max instead variadic

This commit is contained in:
BlackMATov
2021-01-27 07:51:38 +07:00
parent e3518b0c89
commit a92f42438b
2 changed files with 71 additions and 19 deletions

View File

@@ -86,12 +86,28 @@ namespace vmath_hpp
return x < y ? x : y;
}
template < typename T, typename... Ts >
[[nodiscard]] std::enable_if_t<
std::is_arithmetic_v<T>,
std::common_type_t<T, Ts...>>
constexpr min(T x, T y, Ts... ts) noexcept {
return min(min(x, y), ts...);
template < typename T >
[[nodiscard]] constexpr T min(std::initializer_list<T> xs) {
auto iter = xs.begin();
auto smallest = iter++;
for ( auto last = xs.end(); iter != last; ++iter ) {
if ( *iter < *smallest ) {
smallest = iter;
}
}
return *smallest;
}
template < typename T, class Compare >
[[nodiscard]] constexpr T min(std::initializer_list<T> xs, Compare comp) {
auto iter = xs.begin();
auto smallest = iter++;
for ( auto last = xs.end(); iter != last; ++iter ) {
if ( comp(*iter, *smallest) ) {
smallest = iter;
}
}
return *smallest;
}
template < typename T >
@@ -100,12 +116,28 @@ namespace vmath_hpp
return x < y ? y : x;
}
template < typename T, typename... Ts >
[[nodiscard]] std::enable_if_t<
std::is_arithmetic_v<T>,
std::common_type_t<T, Ts...>>
constexpr max(T x, T y, Ts... ts) noexcept {
return max(max(x, y), ts...);
template < typename T >
[[nodiscard]] constexpr T max(std::initializer_list<T> xs) {
auto iter = xs.begin();
auto largest = iter++;
for ( auto last = xs.end(); iter != last; ++iter ) {
if ( *largest < *iter ) {
largest = iter;
}
}
return *largest;
}
template < typename T, class Compare >
[[nodiscard]] constexpr T max(std::initializer_list<T> xs, Compare comp) {
auto iter = xs.begin();
auto largest = iter++;
for ( auto last = xs.end(); iter != last; ++iter ) {
if ( comp(*largest, *iter) ) {
largest = iter;
}
}
return *largest;
}
template < typename T >
@@ -422,7 +454,7 @@ namespace vmath_hpp
if constexpr ( std::is_floating_point_v<T> ) {
// http://www.realtimecollisiondetection.net/pubs/Tolerances
const T epsilon = std::numeric_limits<T>::epsilon();
return abs(x - y) <= epsilon * max(T(1), abs(x), abs(y));
return abs(x - y) <= epsilon * max({T(1), abs(x), abs(y)});
} else {
return x == y;
}
@@ -433,7 +465,7 @@ namespace vmath_hpp
constexpr approx(T x, T y, T epsilon) noexcept {
if constexpr ( std::is_floating_point_v<T> ) {
// http://www.realtimecollisiondetection.net/pubs/Tolerances
return abs(x - y) <= epsilon * max(T(1), abs(x), abs(y));
return abs(x - y) <= epsilon * max({T(1), abs(x), abs(y)});
} else {
return abs(x - y) <= epsilon;
}

View File

@@ -86,12 +86,32 @@ TEST_CASE("vmath/fun") {
}
STATIC_REQUIRE(min(0.f, 1.f) == uapprox(0.f));
STATIC_REQUIRE(min(3.f, 2.f, 1.f) == uapprox(1.f));
STATIC_REQUIRE(min(4.f, 3.f, 2.f, 1.f) == uapprox(1.f));
STATIC_REQUIRE(max(0.f, 1.f) == uapprox(1.f));
STATIC_REQUIRE(max(3.f, 2.f, 1.f) == uapprox(3.f));
STATIC_REQUIRE(max(4.f, 3.f, 2.f, 1.f) == uapprox(4.f));
STATIC_REQUIRE(min({0.f}) == uapprox(0.f));
STATIC_REQUIRE(min({0.f, 1.f}) == uapprox(0.f));
STATIC_REQUIRE(min({3.f, 2.f, 1.f}) == uapprox(1.f));
STATIC_REQUIRE(min({4.f, 3.f, 2.f, 1.f}) == uapprox(1.f));
STATIC_REQUIRE(min({0.f}, [](auto x, auto y){return x < y;}) == uapprox(0.f));
STATIC_REQUIRE(min({0.f, 1.f}, [](auto x, auto y){return x < y;}) == uapprox(0.f));
STATIC_REQUIRE(min({3.f, 2.f, 1.f}, [](auto x, auto y){return x < y;}) == uapprox(1.f));
STATIC_REQUIRE(min({4.f, 3.f, 2.f, 1.f}, [](auto x, auto y){return x < y;}) == uapprox(1.f));
STATIC_REQUIRE(min({0.f}, [](auto x, auto y){return x > y;}) == uapprox(0.f));
STATIC_REQUIRE(min({0.f, 1.f}, [](auto x, auto y){return x > y;}) == uapprox(1.f));
STATIC_REQUIRE(min({3.f, 2.f, 1.f}, [](auto x, auto y){return x > y;}) == uapprox(3.f));
STATIC_REQUIRE(min({4.f, 3.f, 2.f, 1.f}, [](auto x, auto y){return x > y;}) == uapprox(4.f));
STATIC_REQUIRE(max({0.f}, [](auto x, auto y){return x < y;}) == uapprox(0.f));
STATIC_REQUIRE(max({0.f, 1.f}, [](auto x, auto y){return x < y;}) == uapprox(1.f));
STATIC_REQUIRE(max({3.f, 2.f, 1.f}, [](auto x, auto y){return x < y;}) == uapprox(3.f));
STATIC_REQUIRE(max({4.f, 3.f, 2.f, 1.f}, [](auto x, auto y){return x < y;}) == uapprox(4.f));
STATIC_REQUIRE(max({0.f}, [](auto x, auto y){return x > y;}) == uapprox(0.f));
STATIC_REQUIRE(max({0.f, 1.f}, [](auto x, auto y){return x > y;}) == uapprox(0.f));
STATIC_REQUIRE(max({3.f, 2.f, 1.f}, [](auto x, auto y){return x > y;}) == uapprox(1.f));
STATIC_REQUIRE(max({4.f, 3.f, 2.f, 1.f}, [](auto x, auto y){return x > y;}) == uapprox(1.f));
STATIC_REQUIRE(clamp(1.0f, 2.f, 3.f) == uapprox(2.0f));
STATIC_REQUIRE(clamp(2.5f, 2.f, 3.f) == uapprox(2.5f));