Make Qt::partial_ordering binary-compatible to std::partial_ordering
In particular, match the value of ::unordered to each std library implementation. Legal disclaimer: The values were provided to this author in a comment on QTBUG-118913. This author hereby confirms he didn't look at any of the implementations himself. The stdlib detection macros are taken from existing code in qcompilerdetection.h. I didn't succeed in googling a corresponding marker for MSSTL, and I didn't look at the implementation or Boost.Config to find one, so this patch just assumes MSSTL as a fall-back, which is probably wrong, since we may still have Dinkumware and RougeWave STLs to deal with on embedded platforms. Add tests to ensure the values are the same on all platforms. To maximize coverage, rename qcompare.qdoc to qcompare.cpp and add a bunch of compile-time tests there. These depend in part on bit_cast, which we cannot depend on, so tst_qcompare contains the same tests using memcpy. Fixes: QTBUG-118913 Change-Id: I46c922c8e3ea37d7c01a71361c7a689340f9047d Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>bb10
parent
c8cd9017f6
commit
4b6f757020
|
|
@ -49,7 +49,7 @@ qt_internal_add_module(Core
|
|||
global/archdetect.cpp
|
||||
global/qassert.cpp global/qassert.h
|
||||
global/qcompare_impl.h
|
||||
global/qcompare.h
|
||||
global/qcompare.cpp global/qcompare.h
|
||||
global/qcompilerdetection.h
|
||||
global/qconstructormacros.h
|
||||
global/qcontainerinfo.h
|
||||
|
|
|
|||
|
|
@ -2,6 +2,41 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
#include "qcompare.h"
|
||||
|
||||
#ifdef __cpp_lib_bit_cast
|
||||
#include <bit>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef __cpp_lib_three_way_comparison
|
||||
static_assert(sizeof(std::partial_ordering) == sizeof(Qt::partial_ordering));
|
||||
static_assert(sizeof(std::weak_ordering) == sizeof(Qt::weak_ordering));
|
||||
static_assert(sizeof(std::strong_ordering) == sizeof(Qt::strong_ordering));
|
||||
#ifdef __cpp_lib_bit_cast
|
||||
#define CHECK(type, flag) \
|
||||
static_assert(std::bit_cast<Qt:: type ## _ordering>(std:: type ## _ordering:: flag) \
|
||||
== Qt:: type ## _ordering :: flag); \
|
||||
static_assert(std::bit_cast<std:: type ## _ordering>(Qt:: type ## _ordering:: flag) \
|
||||
== std:: type ## _ordering :: flag) \
|
||||
/* end */
|
||||
CHECK(partial, unordered);
|
||||
CHECK(partial, less);
|
||||
CHECK(partial, greater);
|
||||
CHECK(partial, equivalent);
|
||||
CHECK(weak, less);
|
||||
CHECK(weak, greater);
|
||||
CHECK(weak, equivalent);
|
||||
CHECK(strong, less);
|
||||
CHECK(strong, greater);
|
||||
CHECK(strong, equal);
|
||||
CHECK(strong, equivalent);
|
||||
#undef CHECK
|
||||
#endif // __cpp_lib_bit_cast
|
||||
#endif //__cpp_lib_three_way_comparison
|
||||
|
||||
|
||||
/*!
|
||||
\page comparison-types.html overview
|
||||
\title Comparison types overview
|
||||
|
|
@ -398,7 +433,7 @@
|
|||
\fn Qt::weak_ordering::is_gt (Qt::weak_ordering o)
|
||||
\fn Qt::weak_ordering::is_gteq(Qt::weak_ordering o)
|
||||
|
||||
\include qcompare.qdoc is_eq_table
|
||||
\include qcompare.cpp is_eq_table
|
||||
|
||||
These functions are provided for compatibility with \c{std::weak_ordering}.
|
||||
*/
|
||||
|
|
@ -544,7 +579,7 @@
|
|||
\fn Qt::partial_ordering::is_gt (Qt::partial_ordering o)
|
||||
\fn Qt::partial_ordering::is_gteq(Qt::partial_ordering o)
|
||||
|
||||
\include qcompare.qdoc is_eq_table
|
||||
\include qcompare.cpp is_eq_table
|
||||
|
||||
These functions are provided for compatibility with \c{std::partial_ordering}.
|
||||
*/
|
||||
|
|
@ -697,7 +732,7 @@
|
|||
\fn QPartialOrdering::is_gt (QPartialOrdering o)
|
||||
\fn QPartialOrdering::is_gteq(QPartialOrdering o)
|
||||
|
||||
\include qcompare.qdoc is_eq_table
|
||||
\include qcompare.cpp is_eq_table
|
||||
|
||||
These functions are provided for compatibility with \c{std::partial_ordering}.
|
||||
*/
|
||||
|
|
@ -729,3 +764,5 @@
|
|||
Represents the result of a comparison where the left operand is not ordered
|
||||
with respect to the right operand.
|
||||
*/
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -30,11 +30,23 @@ enum class Ordering : CompareUnderlyingType
|
|||
Greater = 1
|
||||
};
|
||||
|
||||
enum class Uncomparable : CompareUnderlyingType
|
||||
enum class LegacyUncomparable : CompareUnderlyingType
|
||||
{
|
||||
Unordered = -127
|
||||
};
|
||||
|
||||
enum class Uncomparable : CompareUnderlyingType
|
||||
{
|
||||
Unordered =
|
||||
#if defined(_LIBCPP_VERSION) // libc++
|
||||
-127
|
||||
#elif defined(__GLIBCXX__) // libstd++
|
||||
2
|
||||
#else // assume MSSTL
|
||||
-128
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace QtPrivate
|
||||
|
||||
// [cmp.partialord]
|
||||
|
|
@ -112,7 +124,7 @@ public:
|
|||
else if (stdorder == std::partial_ordering::greater)
|
||||
m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
|
||||
else if (stdorder == std::partial_ordering::unordered)
|
||||
m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered);
|
||||
m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered);
|
||||
}
|
||||
|
||||
constexpr Q_IMPLICIT operator std::partial_ordering() const noexcept
|
||||
|
|
@ -123,7 +135,7 @@ public:
|
|||
return std::partial_ordering::equivalent;
|
||||
else if (static_cast<QtPrivate::Ordering>(m_order) == QtPrivate::Ordering::Greater)
|
||||
return std::partial_ordering::greater;
|
||||
else if (static_cast<QtPrivate::Uncomparable>(m_order) == QtPrivate::Uncomparable::Unordered)
|
||||
else if (static_cast<QtPrivate::LegacyUncomparable>(m_order) == QtPrivate::LegacyUncomparable::Unordered)
|
||||
return std::partial_ordering::unordered;
|
||||
return std::partial_ordering::unordered;
|
||||
}
|
||||
|
|
@ -145,7 +157,7 @@ private:
|
|||
constexpr explicit QPartialOrdering(QtPrivate::Ordering order) noexcept
|
||||
: m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
|
||||
{}
|
||||
constexpr explicit QPartialOrdering(QtPrivate::Uncomparable order) noexcept
|
||||
constexpr explicit QPartialOrdering(QtPrivate::LegacyUncomparable order) noexcept
|
||||
: m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
|
||||
{}
|
||||
|
||||
|
|
@ -163,7 +175,7 @@ private:
|
|||
// instead of the exposition only is_ordered member in [cmp.partialord],
|
||||
// use a private function
|
||||
constexpr bool isOrdered() const noexcept
|
||||
{ return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered); }
|
||||
{ return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered); }
|
||||
|
||||
QtPrivate::CompareUnderlyingType m_order;
|
||||
};
|
||||
|
|
@ -171,7 +183,7 @@ private:
|
|||
inline constexpr QPartialOrdering QPartialOrdering::Less(QtPrivate::Ordering::Less);
|
||||
inline constexpr QPartialOrdering QPartialOrdering::Equivalent(QtPrivate::Ordering::Equivalent);
|
||||
inline constexpr QPartialOrdering QPartialOrdering::Greater(QtPrivate::Ordering::Greater);
|
||||
inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::Uncomparable::Unordered);
|
||||
inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::LegacyUncomparable::Unordered);
|
||||
|
||||
namespace Qt {
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class tst_QCompare: public QObject
|
|||
Q_OBJECT
|
||||
private slots:
|
||||
void legacyPartialOrdering();
|
||||
void stdQtBinaryCompatibility();
|
||||
void partialOrdering();
|
||||
void weakOrdering();
|
||||
void strongOrdering();
|
||||
|
|
@ -130,6 +131,44 @@ void tst_QCompare::legacyPartialOrdering()
|
|||
static_assert(!(0 >= QPartialOrdering::Greater));
|
||||
}
|
||||
|
||||
void tst_QCompare::stdQtBinaryCompatibility()
|
||||
{
|
||||
#ifndef __cpp_lib_three_way_comparison
|
||||
QSKIP("This test requires C++20 three-way-comparison support enabled in the stdlib.");
|
||||
#else
|
||||
QCOMPARE_EQ(sizeof(std::partial_ordering), 1U);
|
||||
QCOMPARE_EQ(sizeof( Qt::partial_ordering), 1U);
|
||||
QCOMPARE_EQ(sizeof(std:: weak_ordering), 1U);
|
||||
QCOMPARE_EQ(sizeof( Qt:: weak_ordering), 1U);
|
||||
QCOMPARE_EQ(sizeof(std:: strong_ordering), 1U);
|
||||
QCOMPARE_EQ(sizeof( Qt:: strong_ordering), 1U);
|
||||
|
||||
auto valueOf = [](auto obj) {
|
||||
typename QIntegerForSizeof<decltype(obj)>::Unsigned value;
|
||||
memcpy(&value, &obj, sizeof(obj));
|
||||
return value;
|
||||
};
|
||||
#define CHECK(type, flag) \
|
||||
QCOMPARE_EQ(valueOf( Qt:: type ## _ordering :: flag), \
|
||||
valueOf(std:: type ## _ordering :: flag)) \
|
||||
/* end */
|
||||
CHECK(partial, unordered);
|
||||
CHECK(partial, less);
|
||||
CHECK(partial, greater);
|
||||
CHECK(partial, equivalent);
|
||||
|
||||
CHECK(weak, less);
|
||||
CHECK(weak, greater);
|
||||
CHECK(weak, equivalent);
|
||||
|
||||
CHECK(strong, less);
|
||||
CHECK(strong, greater);
|
||||
CHECK(strong, equivalent);
|
||||
CHECK(strong, equal);
|
||||
#undef CHECK
|
||||
#endif //__cpp_lib_three_way_comparison
|
||||
}
|
||||
|
||||
void tst_QCompare::partialOrdering()
|
||||
{
|
||||
static_assert(Qt::partial_ordering::unordered == Qt::partial_ordering::unordered);
|
||||
|
|
|
|||
Loading…
Reference in New Issue