For any minimum value of a signed type, its negation (with wraparound) results in the same value, behaving like zero. Representing the unordered result with this minimum value, along with 0 for equal, 1 for greater, and -1 for less in partial_ordering, allows its value to be reversed using unary negation.
The operator<=(partial_order, 0) now checks if the reversed value is positive. This works correctly because the unordered value remains unchanged and thus negative. libstdc++-v3/ChangeLog: * libsupc++/compare (_Ncmp::_Unordered): Rename and change the value to minimum value of signed char. (_Ncomp::unordered): Renamed from _Unordered, the name is reserved by partial_ordered::unordered. (partial_ordering::_M_reverse()): Define. (operator<=(partial_ordering, __cmp_cat::__unspec)) (operator>=(__cmp_cat::__unspec, partial_ordering)): Implemented in terms of negated _M_value. (operator>=(partial_ordering, __cmp_cat::__unspec)) (operator<=(__cmp_cat::__unspec, partial_ordering)): Directly compare _M_value, as unordered value is negative. (partial_ordering::unordered): Handle _Ncmp::unoredred rename. --- Changes in v3: * rename and simplify defintion of _Ncmp::unordered * simplify defintion of _M_reverse Testing on x86_64-linux and powerpc64le-linux. OK for trunk when test passes? libstdc++-v3/libsupc++/compare | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare index 82b5c53139c..2624fa9144f 100644 --- a/libstdc++-v3/libsupc++/compare +++ b/libstdc++-v3/libsupc++/compare @@ -56,7 +56,7 @@ namespace std _GLIBCXX_VISIBILITY(default) enum class _Ord : type { equivalent = 0, less = -1, greater = 1 }; - enum class _Ncmp : type { _Unordered = 2 }; + enum class _Ncmp : type { unordered = -__SCHAR_MAX__ - 1 }; struct __unspec { @@ -66,7 +66,7 @@ namespace std _GLIBCXX_VISIBILITY(default) class partial_ordering { - // less=0xff, equiv=0x00, greater=0x01, unordered=0x02 + // less=0xff, equiv=0x00, greater=0x01, unordered=0x80 __cmp_cat::type _M_value; constexpr explicit @@ -82,6 +82,14 @@ namespace std _GLIBCXX_VISIBILITY(default) friend class weak_ordering; friend class strong_ordering; + [[__gnu__::__always_inline__]] + constexpr __cmp_cat::type + _M_reverse() const + { + // leaves _Ncmp::unordered unchanged + return static_cast<__cmp_cat::type>(-_M_value); + } + public: // valid values static const partial_ordering less; @@ -112,12 +120,12 @@ namespace std _GLIBCXX_VISIBILITY(default) [[nodiscard]] friend constexpr bool operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept - { return __v._M_value <= 0; } + { return __v._M_reverse() >= 0; } [[nodiscard]] friend constexpr bool operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept - { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } + { return __v._M_value >= 0; } [[nodiscard]] friend constexpr bool @@ -132,12 +140,12 @@ namespace std _GLIBCXX_VISIBILITY(default) [[nodiscard]] friend constexpr bool operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept - { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } + { return 0 <= __v._M_value; } [[nodiscard]] friend constexpr bool operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept - { return 0 >= __v._M_value; } + { return 0 <= __v._M_reverse(); } [[nodiscard]] friend constexpr partial_ordering @@ -166,7 +174,7 @@ namespace std _GLIBCXX_VISIBILITY(default) partial_ordering::greater(__cmp_cat::_Ord::greater); inline constexpr partial_ordering - partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered); + partial_ordering::unordered(__cmp_cat::_Ncmp::unordered); class weak_ordering { -- 2.50.1