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; return x < y ? x : y;
} }
template < typename T, typename... Ts > template < typename T >
[[nodiscard]] std::enable_if_t< [[nodiscard]] constexpr T min(std::initializer_list<T> xs) {
std::is_arithmetic_v<T>, auto iter = xs.begin();
std::common_type_t<T, Ts...>> auto smallest = iter++;
constexpr min(T x, T y, Ts... ts) noexcept { for ( auto last = xs.end(); iter != last; ++iter ) {
return min(min(x, y), ts...); 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 > template < typename T >
@@ -100,12 +116,28 @@ namespace vmath_hpp
return x < y ? y : x; return x < y ? y : x;
} }
template < typename T, typename... Ts > template < typename T >
[[nodiscard]] std::enable_if_t< [[nodiscard]] constexpr T max(std::initializer_list<T> xs) {
std::is_arithmetic_v<T>, auto iter = xs.begin();
std::common_type_t<T, Ts...>> auto largest = iter++;
constexpr max(T x, T y, Ts... ts) noexcept { for ( auto last = xs.end(); iter != last; ++iter ) {
return max(max(x, y), ts...); 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 > template < typename T >
@@ -422,7 +454,7 @@ namespace vmath_hpp
if constexpr ( std::is_floating_point_v<T> ) { if constexpr ( std::is_floating_point_v<T> ) {
// http://www.realtimecollisiondetection.net/pubs/Tolerances // http://www.realtimecollisiondetection.net/pubs/Tolerances
const T epsilon = std::numeric_limits<T>::epsilon(); 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 { } else {
return x == y; return x == y;
} }
@@ -433,7 +465,7 @@ namespace vmath_hpp
constexpr approx(T x, T y, T epsilon) noexcept { constexpr approx(T x, T y, T epsilon) noexcept {
if constexpr ( std::is_floating_point_v<T> ) { if constexpr ( std::is_floating_point_v<T> ) {
// http://www.realtimecollisiondetection.net/pubs/Tolerances // 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 { } else {
return abs(x - y) <= epsilon; 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(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(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(1.0f, 2.f, 3.f) == uapprox(2.0f));
STATIC_REQUIRE(clamp(2.5f, 2.f, 3.f) == uapprox(2.5f)); STATIC_REQUIRE(clamp(2.5f, 2.f, 3.f) == uapprox(2.5f));