diff --git a/headers/vmath.hpp/vmath_fun.hpp b/headers/vmath.hpp/vmath_fun.hpp index c7b4429..b25da71 100644 --- a/headers/vmath.hpp/vmath_fun.hpp +++ b/headers/vmath.hpp/vmath_fun.hpp @@ -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, - std::common_type_t> - 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 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 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, - std::common_type_t> - 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 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 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 ) { // http://www.realtimecollisiondetection.net/pubs/Tolerances const T epsilon = std::numeric_limits::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 ) { // 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; } diff --git a/untests/vmath_fun_tests.cpp b/untests/vmath_fun_tests.cpp index 390e763..e15b6f1 100644 --- a/untests/vmath_fun_tests.cpp +++ b/untests/vmath_fun_tests.cpp @@ -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));