include/o3tl/compare.hxx | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-)
New commits: commit c1991a5fb229161b5f2ad3240afc5b2417abe5c9 Author: Stephan Bergmann <[email protected]> AuthorDate: Thu Feb 8 09:53:04 2024 +0100 Commit: Stephan Bergmann <[email protected]> CommitDate: Thu Feb 8 22:43:49 2024 +0100 A better approximation of std::strong_order (Unfortunately, the environments that don't have std::strong_order typically also don't have std::bit_cast, so we need to approximate that, too.) Change-Id: I0b6344c83bc8227af090cfe68902acd385f682ff Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163111 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <[email protected]> diff --git a/include/o3tl/compare.hxx b/include/o3tl/compare.hxx index 27c6b31ac647..2b0db4e5be93 100644 --- a/include/o3tl/compare.hxx +++ b/include/o3tl/compare.hxx @@ -12,13 +12,17 @@ #include <sal/config.h> #include <compare> +#include <concepts> +#include <cstdint> +#include <cstring> +#include <limits> #include <config_global.h> namespace o3tl { -// A poor approximation of C++20 <compare> std::strong_order, falling back to operator <=> (so e.g. -// not providing a strict weak ordering for floating-point types with NaN): +// An approximation of C++20 <compare> std::strong_order that should work at least for IEC559 float +// and double on platforms that have correspondingly-sized std::int32_t and std::int64_t: #if HAVE_CPP_STRONG_ORDER inline constexpr auto strong_order = std::strong_order; @@ -27,9 +31,25 @@ inline constexpr auto strong_order = std::strong_order; namespace detail { +template<typename To, typename From> To bit_cast(From val) requires (sizeof (To) == sizeof (From)) { + char buf alignas(To)[sizeof (From)]; + std::memcpy(buf, &val, sizeof (From)); + return *reinterpret_cast<To const *>(buf); +} + struct strong_order { - auto operator()(auto x, auto y) const { return x <=> y; } + template <typename T> auto operator ()(T x, T y) const + requires std::same_as<T, float> && std::numeric_limits<T>::is_iec559 + { + return bit_cast<std::int32_t>(x) <=> bit_cast<std::int32_t>(y); + } + + template <typename T> auto operator ()(T x, T y) const + requires std::same_as<T, double> && std::numeric_limits<T>::is_iec559 + { + return bit_cast<std::int64_t>(x) <=> bit_cast<std::int64_t>(y); + } }; }
