On Wed, 27 Aug 2025 at 07:33, Tomasz Kamiński <tkami...@redhat.com> wrote: > > 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: > static_cast<unsigned char>(static_cast<unsigned int>(-_M_value))). > The static casts are required to avoid undefined behavior from signed > overflow. > > The operator<=(partial_order, zero_type) 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 (__cmp_cat::__utype): Define. > (_Ncmp::_Unordered): Change the value to minimum value of > signed char. > (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. > --- > Tested on x86_64-linux. Testing on powerpc64le. > OK for trunk when test passes? > > libstdc++-v3/libsupc++/compare | 25 +++++++++++++++++++------ > 1 file changed, 19 insertions(+), 6 deletions(-) > > diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare > index 82b5c53139c..ae3a1c5e612 100644 > --- a/libstdc++-v3/libsupc++/compare > +++ b/libstdc++-v3/libsupc++/compare > @@ -53,10 +53,14 @@ namespace std _GLIBCXX_VISIBILITY(default) > namespace __cmp_cat > { > using type = signed char; > + using __utype = unsigned char; > > enum class _Ord : type { equivalent = 0, less = -1, greater = 1 }; > > - enum class _Ncmp : type { _Unordered = 2 }; > + enum class _Ncmp : type { > + // minimum value of signed char, wraparound negation is no-op > + _Unordered = static_cast<type>(static_cast<__utype>(1u << > (__CHAR_BIT__ - 1)))
Oops, I accidentally replied offlist, repeating my comment for "reply all": This could be just (-__SCHAR_MAX__ - 1) which seems simpler and has no UB. Otherwise I really like this change. It's a useful property for the negative of the value to have the correct meaning for reversed args. > + }; > > struct __unspec > { > @@ -66,7 +70,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 +86,15 @@ namespace std _GLIBCXX_VISIBILITY(default) > friend class weak_ordering; > friend class strong_ordering; > > + [[__gnu__::__always_inline__]] > + constexpr __cmp_cat::type > + _M_reverse() const > + { > + return static_cast<__cmp_cat::type>( > + static_cast<__cmp_cat::__utype>( > + static_cast<unsigned int>(-_M_value))); > + } > + > public: > // valid values > static const partial_ordering less; > @@ -112,12 +125,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 +145,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 > -- > 2.50.1 >