From 73db5a58856587fc07664b81559f9ea28e10faac Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 6 Mar 2026 11:47:08 +0100 Subject: [PATCH] Fix greater_equal and less_equal --- include/etl/functional.h | 10 +++--- test/test_functional.cpp | 70 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/include/etl/functional.h b/include/etl/functional.h index 0f0172ec..73b1685b 100644 --- a/include/etl/functional.h +++ b/include/etl/functional.h @@ -224,9 +224,9 @@ namespace etl typedef int is_transparent; template - constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast(lhs) < static_cast(rhs)) + constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(!(static_cast(rhs) < static_cast(lhs))) { - return !(static_cast(lhs) < static_cast(rhs)); + return !(static_cast(rhs) < static_cast(lhs)); } }; #endif @@ -250,7 +250,7 @@ namespace etl typedef int is_transparent; template - constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast(lhs) < static_cast(rhs)) + constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast(rhs) < static_cast(lhs)) { return static_cast(rhs) < static_cast(lhs); } @@ -276,9 +276,9 @@ namespace etl typedef int is_transparent; template - constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(static_cast(lhs) < static_cast(rhs)) + constexpr auto operator()(T1&& lhs, T2&& rhs) const -> decltype(!(static_cast(lhs) < static_cast(rhs))) { - return static_cast(rhs) < static_cast(lhs); + return !(static_cast(lhs) < static_cast(rhs)); } }; #endif diff --git a/test/test_functional.cpp b/test/test_functional.cpp index 1204d330..5bbe6beb 100644 --- a/test/test_functional.cpp +++ b/test/test_functional.cpp @@ -85,6 +85,24 @@ namespace mutable std::string result; }; +#if ETL_USING_CPP11 + // Lightweight type used to verify transparent heterogeneous comparison. + // Only operator<(int, Wrapper) is defined; operator<(Wrapper, int) is + // intentionally absent. less_equal is implemented as + // !(rhs < lhs), so less_equal{}(Wrapper, int) needs + // operator<(int, Wrapper) which IS provided. + struct Wrapper + { + int value; + constexpr explicit Wrapper(int v) : value(v) {} + }; + + // int < Wrapper -- defined + constexpr bool operator<(int lhs, const Wrapper& rhs) { return lhs < rhs.value; } + + // Wrapper < int -- intentionally NOT defined +#endif + SUITE(test_functional) { //************************************************************************* @@ -101,6 +119,32 @@ namespace CHECK((compare>(1, 2))); CHECK(!(compare>(2, 1))); CHECK((compare>(1, 1))); + +#if ETL_USING_CPP11 + CHECK((compare>(1, 2))); + CHECK(!(compare>(2, 1))); + CHECK((compare>(1, 1))); +#endif + } + + //************************************************************************* + TEST(test_less_equal_void_heterogeneous) + { +#if ETL_USING_CPP11 + // less_equal{}(lhs, rhs) is !(rhs < lhs). + // With only operator<(int, Wrapper) defined, we can call + // less_equal{}(Wrapper, int) because the implementation + // evaluates !(int < Wrapper). + + // Wrapper(1) <= 2 → !(2 < Wrapper(1)) → !(2 < 1) → !false → true + CHECK((etl::less_equal{}(Wrapper(1), 2))); + + // Wrapper(2) <= 1 → !(1 < Wrapper(2)) → !(1 < 2) → !true → false + CHECK(!(etl::less_equal{}(Wrapper(2), 1))); + + // Wrapper(3) <= 3 → !(3 < Wrapper(3)) → !(3 < 3) → !false → true + CHECK((etl::less_equal{}(Wrapper(3), 3))); +#endif } //************************************************************************* @@ -117,6 +161,32 @@ namespace CHECK(!(compare>(1, 2))); CHECK((compare>(2, 1))); CHECK((compare>(1, 1))); + +#if ETL_USING_CPP11 + CHECK(!(compare>(1, 2))); + CHECK((compare>(2, 1))); + CHECK((compare>(1, 1))); +#endif + } + + //************************************************************************* + TEST(test_greater_equal_void_heterogeneous) + { +#if ETL_USING_CPP11 + // greater_equal{}(lhs, rhs) is !(lhs < rhs). + // With only operator<(int, Wrapper) defined, we can call + // greater_equal{}(int, Wrapper) because the implementation + // evaluates !(int < Wrapper). + + // 2 >= Wrapper(1) → !(2 < Wrapper(1)) → !(2 < 1) → !false → true + CHECK((etl::greater_equal{}(2, Wrapper(1)))); + + // 1 >= Wrapper(2) → !(1 < Wrapper(2)) → !(1 < 2) → !true → false + CHECK(!(etl::greater_equal{}(1, Wrapper(2)))); + + // 3 >= Wrapper(3) → !(3 < Wrapper(3)) → !(3 < 3) → !false → true + CHECK((etl::greater_equal{}(3, Wrapper(3)))); +#endif } //*************************************************************************