On Thu, 28 Aug 2025 at 11:13, Tomasz Kamiński <tkami...@redhat.com> wrote: > > This patch adds two new internal helpers for ordering types: > * __cmp_cat::__ord to retrieve an internal _Ord value, > * __cmp_cat::__make<Ordering> to create an ordering from an _Ord value. > > Conversions between ordering types are now handled by __cmp_cat::__make. As a > result, ordering types no longer need to befriend each other, only the new > helpers. > > The __fp_weak_ordering implementation has also been simplified by: > * using the new helpers to convert partial_ordering to weak_ordering, > * using strong_ordering to weak_ordering conversion operator, > for the __isnan_sign comparison, > * removing the unused __cat local variable. > > Finally, the _Ncmp enum is removed, and the unordered enumerator is added > to the existing _Ord enum. > > libstdc++-v3/ChangeLog: > > * libsupc++/compare (__cmp_cat::_Ord): Add unordered enumerator. > (__cmp_cat::_Ncmp): Remove. > (__cmp_cat::__ord, __cmp_cat::__make): Define. > (partial_ordering::partial_ordering(__cmp_cat::_Ncmp)): Remove. > (operator<=>(__cmp_cat::__unspec, partial_ordering)) > (partial_ordering::unordered): Replace _Ncmp with _Ord. > (std::partial_ordering, std::weak_ordering, std::strong_ordering): > Befriend __ord and __make helpers, remove friend declartions for > other orderings. > (__compare::__fp_weak_ordering): Remove unused __cat variable. > Simplify ordering conversions. > --- > I bundled the removal of _N_cmp and putting unordered in _Ord here, > it is related, as new helpers now cleary can operate with one enumerator. > > Tested on x86_64-linux locally. Testing on powerpc64le. > OK for trunk? > > libstdc++-v3/libsupc++/compare | 79 +++++++++++++++------------------- > 1 file changed, 35 insertions(+), 44 deletions(-) > > diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare > index ef0f0376964..7722e205190 100644 > --- a/libstdc++-v3/libsupc++/compare > +++ b/libstdc++-v3/libsupc++/compare > @@ -54,9 +54,24 @@ namespace std _GLIBCXX_VISIBILITY(default) > { > using type = signed char; > > - enum class _Ord : type { equivalent = 0, less = -1, greater = 1 }; > + enum class _Ord : type > + { > + equivalent = 0, less = -1, greater = 1, > + // value remains unchanged when negated > + unordered = -__SCHAR_MAX__ - 1 > + }; > > - enum class _Ncmp : type { unordered = -__SCHAR_MAX__ - 1 }; > + template<typename _Ordering> > + [[__gnu__::__always_inline__]] > + constexpr _Ord > + __ord(_Ordering __o) > + { return _Ord(__o._M_value); } > + > + template<typename _Ordering> > + [[__gnu__::__always_inline__]] > + constexpr _Ordering > + __make(_Ord __o) > + { return _Ordering(__o); }
I think we might as well add noexcept to these helper functions. The constructors that use them are noexcept already, and it might mean Clang doesn't add a try-catch to those constructors. OK with that change. > > struct __unspec > { > @@ -74,22 +89,17 @@ namespace std _GLIBCXX_VISIBILITY(default) > : _M_value(__cmp_cat::type(__v)) > { } > > - constexpr explicit > - partial_ordering(__cmp_cat::_Ncmp __v) noexcept > - : _M_value(__cmp_cat::type(__v)) > - { } > - > - friend class weak_ordering; > - friend class strong_ordering; > - > [[__gnu__::__always_inline__]] > constexpr __cmp_cat::type > _M_reverse() const > { > - // leaves _Ncmp::unordered unchanged > + // leaves _Ord::unordered unchanged > return static_cast<__cmp_cat::type>(-_M_value); > } > > + friend constexpr __cmp_cat::_Ord __cmp_cat::__ord<>(partial_ordering); > + friend constexpr partial_ordering __cmp_cat::__make<>(__cmp_cat::_Ord); > + > public: > // valid values > static const partial_ordering less; > @@ -155,7 +165,7 @@ namespace std _GLIBCXX_VISIBILITY(default) > [[nodiscard]] > friend constexpr partial_ordering > operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept > - { return partial_ordering(__cmp_cat::_Ncmp(__v._M_reverse())); } > + { return partial_ordering(__cmp_cat::_Ord(__v._M_reverse())); } > }; > > // valid values' definitions > @@ -169,7 +179,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::_Ord::unordered); > > class weak_ordering > { > @@ -179,7 +189,8 @@ namespace std _GLIBCXX_VISIBILITY(default) > weak_ordering(__cmp_cat::_Ord __v) noexcept : > _M_value(__cmp_cat::type(__v)) > { } > > - friend class strong_ordering; > + friend constexpr __cmp_cat::_Ord __cmp_cat::__ord<>(weak_ordering); > + friend constexpr weak_ordering __cmp_cat::__make<>(__cmp_cat::_Ord); > > public: > // valid values > @@ -189,7 +200,7 @@ namespace std _GLIBCXX_VISIBILITY(default) > > [[nodiscard]] > constexpr operator partial_ordering() const noexcept > - { return partial_ordering(__cmp_cat::_Ord(_M_value)); } > + { return __cmp_cat::__make<partial_ordering>(__cmp_cat::_Ord(_M_value)); > } > > // comparisons > [[nodiscard]] > @@ -271,6 +282,9 @@ namespace std _GLIBCXX_VISIBILITY(default) > : _M_value(__cmp_cat::type(__v)) > { } > > + friend constexpr __cmp_cat::_Ord __cmp_cat::__ord<>(strong_ordering); > + friend constexpr strong_ordering __cmp_cat::__make<>(__cmp_cat::_Ord); > + > public: > // valid values > static const strong_ordering less; > @@ -280,11 +294,11 @@ namespace std _GLIBCXX_VISIBILITY(default) > > [[nodiscard]] > constexpr operator partial_ordering() const noexcept > - { return partial_ordering(__cmp_cat::_Ord(_M_value)); } > + { return __cmp_cat::__make<partial_ordering>(__cmp_cat::_Ord(_M_value)); > } > > [[nodiscard]] > constexpr operator weak_ordering() const noexcept > - { return weak_ordering(__cmp_cat::_Ord(_M_value)); } > + { return __cmp_cat::__make<weak_ordering>(__cmp_cat::_Ord(_M_value)); } > > // comparisons > [[nodiscard]] > @@ -584,26 +598,9 @@ namespace std _GLIBCXX_VISIBILITY(default) > constexpr weak_ordering > __fp_weak_ordering(_Tp __e, _Tp __f) > { > - // Returns an integer with the same sign as the argument, and > magnitude > - // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5 > - auto __cat = [](_Tp __fp) -> int { > - const int __sign = __builtin_signbit(__fp) ? -1 : 1; > - if (__builtin_isnormal(__fp)) > - return (__fp == 0 ? 1 : 3) * __sign; > - if (__builtin_isnan(__fp)) > - return 5 * __sign; > - if (int __inf = __builtin_isinf_sign(__fp)) > - return 4 * __inf; > - return 2 * __sign; > - }; > - > - auto __po = __e <=> __f; > - if (is_lt(__po)) > - return weak_ordering::less; > - else if (is_gt(__po)) > - return weak_ordering::greater; > - else if (__po == partial_ordering::equivalent) > - return weak_ordering::equivalent; > + auto __po = __cmp_cat::__ord(__e <=> __f); > + if (__po != __cmp_cat::_Ord::unordered) > + return __cmp_cat::__make<weak_ordering>(__po); > else // unordered, at least one argument is NaN > { > // return -1 for negative nan, +1 for positive nan, 0 otherwise. > @@ -612,13 +609,7 @@ namespace std _GLIBCXX_VISIBILITY(default) > ? __builtin_signbit(__fp) ? -1 : 1 > : 0; > }; > - auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f); > - if (is_eq(__ord)) > - return weak_ordering::equivalent; > - else if (is_lt(__ord)) > - return weak_ordering::less; > - else > - return weak_ordering::greater; > + return __isnan_sign(__e) <=> __isnan_sign(__f); > } > } > > -- > 2.50.1 >