From 03e78e5d624d9752d76c7448d58c9d9d15a4dc18 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 26 May 2023 13:15:44 +0200 Subject: [PATCH] Long live QSpan as public API! Provide qspan_p.h as backward-compatibility header. [ChangeLog][QtCore][QSpan] New Qt equivalent of std::span. Fixes: QTBUG-115022 Change-Id: I1cc27dc0aa1f7406f0a41d7a75f176cd7f858feb Reviewed-by: Ivan Solovev Reviewed-by: Thiago Macieira --- src/corelib/CMakeLists.txt | 1 + src/corelib/text/qstring.cpp | 2 +- src/corelib/tools/qcontainerfwd.h | 2 + src/corelib/tools/qspan.h | 424 ++++++++++++ src/corelib/tools/qspan.qdoc | 639 ++++++++++++++++++ src/corelib/tools/qspan_p.h | 403 +---------- src/gui/text/qtextengine_p.h | 2 +- .../qmimedatabase/tst_qmimedatabase.cpp | 2 +- tests/auto/corelib/tools/qspan/CMakeLists.txt | 2 - tests/auto/corelib/tools/qspan/tst_qspan.cpp | 2 +- 10 files changed, 1072 insertions(+), 407 deletions(-) create mode 100644 src/corelib/tools/qspan.h create mode 100644 src/corelib/tools/qspan.qdoc diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 656c4f777d8..544d58d1747 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -307,6 +307,7 @@ qt_internal_add_module(Core tools/qsharedpointer.cpp tools/qsharedpointer.h tools/qsharedpointer_impl.h tools/qsize.cpp tools/qsize.h + tools/qspan.h tools/qspan_p.h tools/qstack.h tools/qtaggedpointer.h diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 0ff1738f517..0b332aa3fb2 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -17,6 +17,7 @@ #include #include "qlocale.h" #include "qlocale_p.h" +#include "qspan.h" #include "qstringbuilder.h" #include "qstringmatcher.h" #include "qvarlengtharray.h" @@ -30,7 +31,6 @@ #endif #include -#include #include #include diff --git a/src/corelib/tools/qcontainerfwd.h b/src/corelib/tools/qcontainerfwd.h index 013ba9eab06..0d9403104fa 100644 --- a/src/corelib/tools/qcontainerfwd.h +++ b/src/corelib/tools/qcontainerfwd.h @@ -12,6 +12,7 @@ #endif // std headers can unfortunately not be forward declared +#include // std::size_t #include QT_BEGIN_NAMESPACE @@ -25,6 +26,7 @@ template using QPair = std::pair; template class QQueue; template class QSet; +template class QSpan; template class QStack; template class QVarLengthArray; template class QList; diff --git a/src/corelib/tools/qspan.h b/src/corelib/tools/qspan.h new file mode 100644 index 00000000000..35f44ebd87b --- /dev/null +++ b/src/corelib/tools/qspan.h @@ -0,0 +1,424 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QSPAN_H +#define QSPAN_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef __cpp_lib_span +#include +#endif +#include + +QT_BEGIN_NAMESPACE + +// like std::dynamic_extent +namespace q20 { + inline constexpr auto dynamic_extent = std::size_t(-1); +} // namespace q20 + +QT_BEGIN_INCLUDE_NAMESPACE +#ifdef __cpp_lib_span +#ifdef __cpp_lib_concepts +namespace std::ranges { +// Officially, these are defined in , but that is a heavy-hitter header. +// OTOH, must specialize these variable templates, too, so we assume that +// includes some meaningful subset of and just go ahead and use them: +template +constexpr inline bool enable_borrowed_range> = true; +template +constexpr inline bool enable_view> = true; +} // namespace std::ranges +#endif // __cpp_lib_concepts +#endif // __cpp_lib_span +QT_END_INCLUDE_NAMESPACE + +namespace QSpanPrivate { + +template class QSpanBase; + +template +struct is_qspan_helper : std::false_type {}; +template +struct is_qspan_helper> : std::true_type {}; +template +struct is_qspan_helper> : std::true_type {}; +template +using is_qspan = is_qspan_helper>; + +template +struct is_std_span_helper : std::false_type {}; +#ifdef __cpp_lib_span +template +struct is_std_span_helper> : std::true_type {}; +#endif // __cpp_lib_span +template +using is_std_span = is_std_span_helper>; + +template +struct is_std_array_helper : std::false_type {}; +template +struct is_std_array_helper> : std::true_type {}; +template +using is_std_array = is_std_array_helper>; + +template +using is_qualification_conversion = + std::is_convertible; // https://eel.is/c++draft/span.cons#note-1 +template +constexpr inline bool is_qualification_conversion_v = is_qualification_conversion::value; + +// Replacements for std::ranges::XXX(), but only bringing in ADL XXX()s, +// not doing the extra work C++20 requires +template +decltype(auto) adl_begin(Range &&r) { using std::begin; return begin(r); } +template +decltype(auto) adl_data(Range &&r) { using std::data; return data(r); } +template +decltype(auto) adl_size(Range &&r) { using std::size; return size(r); } + +// Replacement for std::ranges::iterator_t (which depends on C++20 std::ranges::begin) +// This one uses adl_begin() instead. +template +using iterator_t = decltype(QSpanPrivate::adl_begin(std::declval())); +template +using range_reference_t = q20::iter_reference_t>; + +template +class QSpanCommon { +protected: + template + using is_compatible_iterator = std::conjunction< + std::is_base_of< + std::random_access_iterator_tag, + typename std::iterator_traits::iterator_category + >, + is_qualification_conversion< + std::remove_reference_t>, + T + > + >; + template + using is_compatible_iterator_and_sentinel = std::conjunction< + is_compatible_iterator, + std::negation> + >; + template // wrap use of SFINAE-unfriendly iterator_t: + struct is_compatible_range_helper : std::false_type {}; + template + struct is_compatible_range_helper>> + : is_compatible_iterator> {}; + template + using is_compatible_range = std::conjunction< + // ### this needs more work, esp. extension to C++20 contiguous iterators + std::negation>, + std::negation>, + std::negation>, + std::negation>>, + is_compatible_range_helper + >; + + // constraints + template + using if_compatible_iterator = std::enable_if_t< + is_compatible_iterator::value + , bool>; + template + using if_compatible_iterator_and_sentinel = std::enable_if_t< + is_compatible_iterator_and_sentinel::value + , bool>; + template + using if_compatible_range = std::enable_if_t::value, bool>; +}; // class QSpanCommon + +template +class QSpanBase : protected QSpanCommon +{ + static_assert(E < size_t{(std::numeric_limits::max)()}, + "QSpan only supports extents that fit into the signed size type (qsizetype)."); + + struct Enabled_t { explicit Enabled_t() = default; }; + static inline constexpr Enabled_t Enable{}; + + template + using if_compatible_array = std::enable_if_t< + N == E && is_qualification_conversion_v + , bool>; + + template + using if_qualification_conversion = std::enable_if_t< + is_qualification_conversion_v + , bool>; +protected: + using Base = QSpanCommon; + + // data members: + T *m_data; + static constexpr qsizetype m_size = qsizetype(E); + + // types and constants: + // (in QSpan only) + + // constructors (need to be public d/t the way ctor inheriting works): +public: + template = true> + Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr} {} + + template = true> + explicit constexpr QSpanBase(It first, qsizetype count) + : m_data{q20::to_address(first)} + { + Q_ASSERT(count == m_size); + } + + template = true> + explicit constexpr QSpanBase(It first, End last) + : QSpanBase(first, last - first) {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t (&arr)[N]) noexcept + : QSpanBase(arr, N) {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(std::array &arr) noexcept + : QSpanBase(arr.data(), N) {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(const std::array &arr) noexcept + : QSpanBase(arr.data(), N) {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(Range &&r) + : QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either) + qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>() + {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(QSpan other) noexcept + : QSpanBase(other.data(), other.size()) + {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(QSpan other) + : QSpanBase(other.data(), other.size()) + {} + +#ifdef __cpp_lib_span + template = true> + Q_IMPLICIT constexpr QSpanBase(std::span other) noexcept + : QSpanBase(other.data(), other.size()) + {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(std::span other) + : QSpanBase(other.data(), other.size()) + {} +#endif // __cpp_lib_span +}; // class QSpanBase (fixed extent) + +template +class QSpanBase : protected QSpanCommon +{ + template + using if_qualification_conversion = std::enable_if_t< + is_qualification_conversion_v + , bool>; +protected: + using Base = QSpanCommon; + + // data members: + T *m_data; + qsizetype m_size; + + // constructors (need to be public d/t the way ctor inheriting works): +public: + Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr}, m_size{0} {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(It first, qsizetype count) + : m_data{q20::to_address(first)}, m_size{count} {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(It first, End last) + : QSpanBase(first, last - first) {} + + template + Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t (&arr)[N]) noexcept + : QSpanBase(arr, N) {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(std::array &arr) noexcept + : QSpanBase(arr.data(), N) {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(const std::array &arr) noexcept + : QSpanBase(arr.data(), N) {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(Range &&r) + : QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either) + qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>() + {} + + template = true> + Q_IMPLICIT constexpr QSpanBase(QSpan other) noexcept + : QSpanBase(other.data(), other.size()) + {} + +#if __cpp_lib_span + template = true> + Q_IMPLICIT constexpr QSpanBase(std::span other) noexcept + : QSpanBase(other.data(), other.size()) + {} +#endif // __cpp_lib_span +}; // class QSpanBase (dynamic extent) + +} // namespace QSpanPrivate + +template +class QSpan +#ifndef Q_QDOC + : private QSpanPrivate::QSpanBase +#endif +{ + using Base = QSpanPrivate::QSpanBase; + Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0, + [[maybe_unused]] qsizetype n = 1) const + { + Q_ASSERT(pos >= 0); + Q_ASSERT(pos <= size()); + Q_ASSERT(n >= 0); + Q_ASSERT(n <= size() - pos); + } + + template + static constexpr bool subspan_always_succeeds_v = N <= E && E != q20::dynamic_extent; +public: + // constants and types + using element_type = T; + using value_type = std::remove_cv_t; + using size_type = qsizetype; // difference to std::span + using difference_type = qptrdiff; // difference to std::span + using pointer = element_type*; + using const_pointer = const element_type*; + using reference = element_type&; + using const_reference = const element_type&; + using iterator = pointer; // implementation-defined choice + using const_iterator = const_pointer; // implementation-defined choice + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + static constexpr std::size_t extent = E; + + // [span.cons], constructors, copy, and assignment + using Base::Base; +#ifdef Q_QDOC + template using if_compatible_iterator = bool; + template using if_qualification_conversion = bool; + template using if_compatible_range = bool; + template = true> constexpr QSpan(It first, qsizetype count); + template = true> constexpr QSpan(It first, It last); + template constexpr QSpan(q20::type_identity_t (&arr)[N]) noexcept; + template = true> constexpr QSpan(std::array &arr) noexcept; + template = true> constexpr QSpan(const std::array &arr) noexcept; + template = true> constexpr QSpan(Range &&r); + template = true> constexpr QSpan(QSpan other) noexcept; + template = true> constexpr QSpan(std::span other) noexcept; +#endif // Q_QDOC + + // [span.obs] + [[nodiscard]] constexpr size_type size() const noexcept { return this->m_size; } + [[nodiscard]] constexpr size_type size_bytes() const noexcept { return size() * sizeof(T); } + [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } + + // [span.elem] + [[nodiscard]] constexpr reference operator[](size_type idx) const + { verify(idx); return data()[idx]; } + [[nodiscard]] constexpr reference front() const { verify(); return *data(); } + [[nodiscard]] constexpr reference back() const { verify(); return data()[size() - 1]; } + [[nodiscard]] constexpr pointer data() const noexcept { return this->m_data; } + + // [span.iterators] + [[nodiscard]] constexpr iterator begin() const noexcept { return data(); } + [[nodiscard]] constexpr iterator end() const noexcept { return data() + size(); } + [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); } + [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); } + [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } + [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } + [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } + [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); } + + // [span.sub] + template + [[nodiscard]] constexpr QSpan first() const + noexcept(subspan_always_succeeds_v) + { + static_assert(Count <= E, + "Count cannot be larger than the span's extent."); + verify(0, Count); + return QSpan{data(), Count}; + } + + template + [[nodiscard]] constexpr QSpan last() const + noexcept(subspan_always_succeeds_v) + { + static_assert(Count <= E, + "Count cannot be larger than the span's extent."); + verify(0, Count); + return QSpan{data() + (size() - Count), Count}; + } + + template + [[nodiscard]] constexpr auto subspan() const + noexcept(subspan_always_succeeds_v) + { + static_assert(Offset <= E, + "Offset cannot be larger than the span's extent."); + verify(Offset, 0); + if constexpr (E == q20::dynamic_extent) + return QSpan{data() + Offset, qsizetype(size() - Offset)}; + else + return QSpan{data() + Offset, qsizetype(E - Offset)}; + } + + template + [[nodiscard]] constexpr auto subspan() const + noexcept(subspan_always_succeeds_v) + { return subspan().template first(); } + + [[nodiscard]] constexpr QSpan first(size_type n) const { verify(0, n); return {data(), n}; } + [[nodiscard]] constexpr QSpan last(size_type n) const { verify(0, n); return {data() + (size() - n), n}; } + [[nodiscard]] constexpr QSpan subspan(size_type pos) const { verify(pos, 0); return {data() + pos, size() - pos}; } + [[nodiscard]] constexpr QSpan subspan(size_type pos, size_type n) const { return subspan(pos).first(n); } + + // Qt-compatibility API: + [[nodiscard]] bool isEmpty() const noexcept { return empty(); } + // nullary first()/last() clash with first<>() and last<>(), so they're not provided for QSpan + [[nodiscard]] constexpr QSpan sliced(size_type pos) const { return subspan(pos); } + [[nodiscard]] constexpr QSpan sliced(size_type pos, size_type n) const { return subspan(pos, n); } + +}; // class QSpan + +// [span.deduct] +template +QSpan(It, EndOrSize) -> QSpan>>; +template +QSpan(T (&)[N]) -> QSpan; +template +QSpan(std::array &) -> QSpan; +template +QSpan(const std::array &) -> QSpan; +template +QSpan(R&&) -> QSpan>>; + +QT_END_NAMESPACE + +#endif // QSPAN_H diff --git a/src/corelib/tools/qspan.qdoc b/src/corelib/tools/qspan.qdoc new file mode 100644 index 00000000000..59fbc06b9ec --- /dev/null +++ b/src/corelib/tools/qspan.qdoc @@ -0,0 +1,639 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/*! + \class QSpan + \inmodule QtCore + \since 6.7 + \brief A non-owning container over contiguous data. + \ingroup tools + \reentrant + + A QSpan references a contiguous portion of another contiguous container. + It acts as an interface type for all kinds of contiguous containers, + without the need to construct an owning container such as QList or + std::vector first. + + The data referenced by a QSpan may be represented as an array (or + array-compatible data-structure such as QList, std::vector, + QVarLengthArray, etc.). QSpan itself merely stores a pointer to the data, + so users must ensure that QSpan objects do not outlive the data they + reference. + + Unlike views such as QStringView, QLatin1StringView and QUtf8StringView, + referenced data can be modified through a QSpan object. To prevent this, + construct a QSpan over a \c{const T}: + + \code + int numbers[] = {0, 1, 2}; + QSpan span = numbers; + span[0] = 42; + // numbers == {42, 1, 2}; + QSpan cspan = numbers; + cspan[0] = 0; // ERROR: cspan[0] is read-only + \endcode + + A QSpan can be \e{fixed-size} or \e{variable-sized}. + + A variable-sized span is formed by omitting the second template argument + (or setting it to \c{std::dynamic_extent}, which is, however, only + available in C++20 builds), as seen in the example above. + + A fixed-size span is formed by passing a number as the second template + argument: + + \code + int numbers[] = {0, 1, 2}; + QSpan span = numbers; + QSpan = numbers; // also OK + \endcode + + As the name suggests, a fixed-size span's size() is fixed at compile-time + whereas the size() of a variable-sized span is determined only at run-time. + + A fixed-size span is not default-constructible (unless its \l extent is zero + (0)). A variable-sized span \e{is} default-constructible and will have + \c{data() == nullptr} and \c{size() == 0}. + + A fixed-size span can be implicitly converted into a variable-sized one. + The opposite direction (variable-length into fixed-length) has the + precondition that both span's sizes must match. + + Unlike with owning containers, \c{const} is \e{shallow} in QSpan: you can + still modify the data through a const QSpan (but not through a + \c{QSpan}), and begin() and end() are not overloaded on + \c{const}/non-\c{const}. There are cbegin() and cend(), though, that return + const_iterators which prevent modification of the data even though \c{T} is + not const: + \code + int numbers[] = {0, 1, 2}; + const QSpan span = numbers; + span.front() = 42; // OK, numbers[0] == 42 now + *span.begin() = 31; // OK, numbers[0] == 31 now + *span.cbegin() = -1; // ERROR: cannot assign through a const_iterator + \endcode + + QSpan should be passed by value, not by reference-to-const: + + \code + void consume(QSpan data); // OK + void consume(const QSpan &data); // works, but is non-idiomatic and less efficient + \endcode + + \c{QSpan} is a \e{Literal Type}, regardless of whether \c{T} is a + Literal Type or not. + + \section2 QSpan vs. std::span + \target span-STL + + QSpan is closely modelled after + \l{https://en.cppreference.com/w/cpp/container/span}{std::span}, but has a + few differences which we'll discuss here. Since they both implicitly + convert into each other, you're free to choose whichever one you like best + in your own code. + + \list + \li QSpan is using the signed qsizetype as \c{size_type} + whereas \c{std::span} uses \c{size_t}. + \li All QSpan constructors are implicit; + many \c{std::span} ones are \c{explicit}. + \li QSpan can be constructed from rvalue owning containers, \c{std::span} can not. + \endlist + + The last two are required for source-compatibility when functions that took + owning containers are converted to take QSpan instead, which is a + vitally-important use-case in Qt. The use of qsizetype is for consistency + with the rest of Qt containers. QSpan template arguments still use size_t + to avoid introducing unnecessary error conditions (negative sizes). + + \section2 Compatible Iterators + \target span-compatible-iterators + + QSpan can be constructed from an iterator and size or from an + iterator pair, provided the iterators are \e{compatible} ones. + Eventually, this should mean C++20 \c{std::contiguous_iterator} and + \c{std::sentinel_for}, but while Qt still supports C++17, only raw pointers + are considered contiguous iterators. + + \section2 Compatible Ranges + \target span-compatible-ranges + + QSpan can also be constructed from a \e{compatible} range. A range is + compatible if it has \l{span-compatible-iterators}{compatible iterators}. + + \sa QList, QStringView, QLatin1StringView, QUtf8StringView +*/ + +// +// Nested types and constants +// + +/*! + \typedef QSpan::element_type + + An alias for \c{T}. Includes the \c{const}, if any. + + This alias is provided for compatbility with the STL. + + \sa value_type, pointer +*/ + +/*! + \typedef QSpan::value_type + + An alias for \c{T}. Excludes the \c{const}, if any. + + This alias is provided for compatbility with the STL. + + \sa element_type +*/ + +/*! + \typedef QSpan::size_type + + An alias for qsizetype. This \l{span-STL}{differs from \c{std::span}}. + + This alias is provided for compatbility with the STL. +*/ + +/*! + \typedef QSpan::difference_type + + An alias for qptrdiff. This \l{span-STL}{differs from \c{std::span}}. + + This alias is provided for compatbility with the STL. +*/ + +/*! + \typedef QSpan::pointer + + An alias for \c{T*} and \c{element_type*}, respectively. Includes the \c{const}, if any. + + This alias is provided for compatbility with the STL. + + \sa element_type, const_pointer, reference, iterator +*/ + +/*! + \typedef QSpan::const_pointer + + An alias for \c{const T*} and \c{const element_type*}, respectively. + + This alias is provided for compatbility with the STL. + + \sa element_type, pointer, const_reference, const_iterator +*/ + +/*! + \typedef QSpan::reference + + An alias for \c{T&} and \c{element_type&}, respectively. Includes the \c{const}, if any. + + This alias is provided for compatbility with the STL. + + \sa element_type, const_reference, pointer +*/ + +/*! + \typedef QSpan::const_reference + + An alias for \c{const T&} and \c{const element_type&}, respectively. + + This alias is provided for compatbility with the STL. + + \sa element_type, reference, const_pointer +*/ + +/*! + \typedef QSpan::iterator + + An alias for \c{T*} and \c{pointer}, respectively. Includes the \c{const}, if any. + + \sa pointer, const_iterator, reverse_iterator +*/ + +/*! + \typedef QSpan::const_iterator + + An alias for \c{const T*} and \c{const_pointer}, respectively. + + \sa const_pointer, iterator, const_reverse_iterator +*/ + +/*! + \typedef QSpan::reverse_iterator + + An alias for \c{std::reverse_iterator}. Includes the \c{const}, if any. + + \sa iterator, const_reverse_iterator +*/ + +/*! + \typedef QSpan::const_reverse_iterator + + An alias for \c{std::reverse_iterator}. + + \sa const_iterator, reverse_iterator +*/ + +/*! + \variable QSpan::extent + + The second template argument of \c{QSpan}, that is, \c{E}. This is + \c{std::dynamic_extent} for variable-sized spans. + + \note While all other sizes and indexes in QSpan use qsizetype, this + variable, like \c{E}, is actually of type \c{size_t}, for compatibility with + \c{std::span} and \c{std::dynamic_extent}. + + \sa size() +*/ + +// +// Constructors and SMFs +// + +/*! + \fn template QSpan::QSpan() + + Default constructor. + + This constructor is only present if \c{E} is either zero (0) or + \c{std::dynamic_extent}. In other words: only fixed-zero-sized or variable-sized spans + are default-constructible. + + \sa extent +*/ + +/*! + \fn template QSpan::QSpan(const QSpan &other) + \fn template QSpan::QSpan(QSpan &&other) + \fn template QSpan &QSpan::operator=(const QSpan &other) + \fn template QSpan &QSpan::operator=(QSpan &&other) + \fn template QSpan::~QSpan() + + These Special Member Functions are implicitly-defined. + + \note Moves are equivalent to copies. Only data() and size() are copied + from span to span, not the referenced data. +*/ + +/*! + \fn template template > QSpan::QSpan(It first, qsizetype count) + + Constructs a QSpan referencing the data starting at \a first and having length + \a count. + + \c{[first, count)} must be a valid range. + + \note This constructor participates in overload resolution only if \c{It} + is \l{span-compatible-iterators}{a compatible iterator}. +*/ + +/*! + \fn template template > QSpan::QSpan(It first, It last) + + Constructs a QSpan referencing the data starting at \a first and having length + (\a last - \a first). + + \c{[first, last)} must be a valid range. + + \note This constructor participates in overload resolution only if \c{It} + is \l{span-compatible-iterators}{a compatible iterator}. +*/ + +/*! + \fn template template QSpan::QSpan(q20::type_identity_t (&arr)[N]); + \fn template template = true> QSpan::QSpan(std::array &arr); + \fn template template = true> QSpan::QSpan(const std::array &arr); + + Constructs a QSpan referencing the data in the supplied array \a arr. + + \note This constructor participates in overload resolution only if + \list + \li either \c{N} or \l{extent} are \c{std::dynamic_extent} or otherwise \l{extent} \c{==} \c{N} + \li and either \c{S} or \c{const S} are the same as \c{T}. + \endlist + + \note \c{q20::type_identity_t} is a C++17 backport of C++20's + \l{https://en.cppreference.com/w/cpp/types/type_identity}{\c{std::type_identity_t}}. +*/ + +/*! + \fn template template = true> QSpan::QSpan(Range &&r) + + Constructs a QSpan referencing the data in the supplied range \a r. + + \note This constructor participates in overload resolution only if \c{Range} + is \l{span-compatible-ranges}{a compatible range}. +*/ + +/*! + \fn template template = true> QSpan::QSpan(QSpan other); + \fn template template = true> QSpan::QSpan(std::span other); + + Constructs a QSpan referencing the data in the supplied span \a other. + + \note This constructor participates in overload resolution only if + \list + \li either \c{N} or \l{extent} are \c{std::dynamic_extent} or \l{extent} \c{==} \c{N} + \li and either \c{S} or \c{const S} are the same as \c{T}. + \endlist +*/ + +// +// Member functions: sizes +// + +/*! + \fn template QSpan::size() const + + Returns the size of the span, that is, the number of elements it references. + + \sa size_bytes(), empty(), isEmpty() +*/ + +/*! + \fn template QSpan::size_bytes() const + + Returns the size of the span in bytes, that is, the number of elements + multiplied by \c{sizeof(T)}. + + \sa size(), empty(), isEmpty() +*/ + +/*! + \fn template QSpan::empty() const + \fn template QSpan::isEmpty() const + + Returns whether the span is empty, that is, whether \c{size() == 0}. + + These functions do the same thing: empty() is provided for STL + compatibility and isEmpty() is provided for Qt compatibility. + + \sa size(), size_bytes() +*/ + +// +// element access +// + +/*! + \fn template QSpan::operator[](size_type idx) const + + Returns a reference to the element at index \a idx in the span. + + The index must be in range, that is, \a idx >= 0 and \a idx < size(), + otherwise the behavior is undefined. + + \sa front(), back(), size(), empty() +*/ + +/*! + \fn template QSpan::front() const + + Returns a reference to the first element in the span. + + The span must not be empty, otherwise the behavior is undefined. + + \sa operator[](), back(), size(), empty() +*/ + +/*! + \fn template QSpan::back() const + + Returns a reference to the last element in the span. + + The span must not be empty, otherwise the behavior is undefined. + + \sa operator[](), front(), size(), empty() +*/ + +/*! + \fn template QSpan::data() const + + Returns a pointer to the beginning of the span. + + The same as calling begin(). + + \sa begin(), front() +*/ + +// +// iterators +// + +/*! + \fn template QSpan::begin() const + + Returns an interator pointing at the beginning of the span. + + Because QSpan iterators are just pointers, this is the same as calling + data(). + + \sa end(), cbegin(), rbegin(), crbegin(), data() +*/ + +/*! + \fn template QSpan::end() const + + Returns an iterator pointing to one past the end of the span. + + Because QSpan iterators are just pointers, this it the same as calling + \c{data() + size()}. + + \sa begin(), cend(), rend(), crend(), data(), size() +*/ + +/*! + \fn template QSpan::cbegin() const + + Returns a const_iterator pointing to the beginning of the span. + + This will return a read-only iterator even if \c{T} is not \c{const}: + \code + QSpan span = ~~~; + *span.begin() = 42; // OK + *span.cbegin() = 42; // ERROR: cannot assign through a const_iterator + \endcode + + \sa cend(), begin(), crbegin(), rbegin(), data() +*/ + +/*! + \fn template QSpan::cend() const + + Returns a const_iterator pointing to one past the end of the span. + + \sa cbegin(), end(), crend(), rend(), data(), size() +*/ + +/*! + \fn template QSpan::rbegin() const + + Returns a reverse_iterator pointing to the beginning of the reversed span. + + \sa rend(), crbegin(), begin(), cbegin() +*/ + +/*! + \fn template QSpan::rend() const + + Returns a reverse_iterator pointing to one past the end of the reversed span. + + \sa rbegin(), crend(), end(), cend() +*/ + +/*! + \fn template QSpan::crbegin() const + + Returns a const_reverse_iterator pointing to the beginning of the reversed span. + + \sa crend(), rbegin(), cbegin(), begin() +*/ + +/*! + \fn template QSpan::crend() const + + Returns a const_reverse_iterator pointing to one past the end of the reversed span. + + \sa crbegin(), rend(), cend(), end() +*/ + +// +// compile-time subspans: +// + +/*! + \fn template template QSpan::first() const + \keyword first-t + + Returns a fixed-sized span of size \c{Count} referencing the first \c{Count} elements of \c{*this}. + + The span must hold at least \c{Count} elements (\c{E} >= \c{Count} \e{and} + size() >= \c{Count}), otherwise the behavior is undefined. + + \sa first(QSpan::size_type), last(), subspan() +*/ + +/*! + \fn template template QSpan::last() const + \keyword last-t + + Returns a fixed-sized span of size \c{Count} referencing the last \c{Count} elements of \c{*this}. + + The span must hold at least \c{Count} elements (\c{E} >= \c{Count} \e{and} + size() >= \c{Count}), otherwise the behavior is undefined. + + \sa last(QSpan::size_type), first(), subspan() +*/ + +/*! + \fn template template QSpan::subspan() const + \keyword subspan-t1 + + Returns a span of size \c{E - Offset} referencing the remainder of this span + after dropping the first \c{Offset} elements. + + If \c{*this} is a variable-sized span, the return type is a variable-sized + span, otherwise it is a fixed-sized span. + + This span must hold at least \c{Offset} elements (\c{E} >= \c{Offset} \e{and} + size() >= \c{Offset}), otherwise the behavior is undefined. + + \sa subspan(QSpan::size_type), subspan(), first(), last() +*/ + +#if 0 // needs fix for QTBUG-118080 integrated into qt5.git +/*! + \fn template template QSpan::subspan() const + \keyword subspan-t2 + + Returns a span of size \c{Count} referencing the \c{Count} elements of this + span starting at \c{Offset}. + + If \c{*this} is a variable-sized span, the return type is a variable-sized + span, otherwise it is a fixed-sized span. + + This span must hold at least \c{Offset + Count} elements (\c{E} >= + \c{Offset + Count} \e{and} size() >= \c{Offset + Count}), otherwise the + behavior is undefined. + + \sa subspan(QSpan::size_type, QSpan::size_type), subspan(), first(), last() +*/ +#endif + +// +// runtime subspans: +// + +/*! + \fn template QSpan::first(qsizetype n) const + \keyword first-n + + Returns a variable-sized span of size \a n referencing the first \a n elements of \c{*this}. + + \a n must be non-negative. + + The span must hold at least \a n elements (\c{E} >= \a n \e{and} size() >= + \a n), otherwise the behavior is undefined. + + \sa {first-t}{first()}, last(QSpan::size_type), subspan(QSpan::size_type), + subspan(QSpan::size_type, QSpan::size_type) + \sa sliced() +*/ + +/*! + \fn template QSpan::last(qsizetype n) const + \keyword last-n + + Returns a variable-sized span of size \a n referencing the last \a n elements of \c{*this}. + + \a n must be non-negative. + + The span must hold at least \a n elements (\c{E} >= \a n \e{and} + size() >= \a n), otherwise the behavior is undefined. + + \sa last(), first(QSpan::size_type), subspan(QSpan::size_type), + subspan(QSpan::size_type, QSpan::size_type), sliced() +*/ + +/*! + \fn template QSpan::subspan(qsizetype pos) const + \fn template QSpan::sliced(qsizetype pos) const + \keyword subspan-n1 + + Returns a variable-sized span of size \c{size() - pos} referencing the + remainder of this span after dropping the first \a pos elements. + + \a pos must be non-negative. + + This span must hold at least \a pos elements (\c{E} >= \a pos \e{and} + size() >= \a pos), otherwise the behavior is undefined. + + These functions do the same thing: subspan() is provided for STL + compatibility and sliced() is provided for Qt compatibility. + + \sa subspan(), first(QSpan::size_type), last(QSpan::size_type) +*/ + +/*! + \fn template QSpan::subspan(qsizetype pos, qsizetype n) const + \fn template QSpan::sliced(qsizetype pos, qsizetype n) const + \keyword subspan-n2 + + Returns a variable-sized span of size \a n referencing the \a n elements of + this span starting at \a pos. + + Both \a pos and \a n must be non-negative. + + This span must hold at least \c{pos + n} elements (\c{E} >= + \c{pos + n} \e{and} size() >= \c{pos + n}), otherwise the + behavior is undefined. + + These functions do the same thing: subspan() is provided for STL + compatibility and sliced() is provided for Qt compatibility. + + \sa subspan(), first(QSpan::size_type), last(QSpan::size_type) +*/ + diff --git a/src/corelib/tools/qspan_p.h b/src/corelib/tools/qspan_p.h index 7b56491a3fb..0072e3ef642 100644 --- a/src/corelib/tools/qspan_p.h +++ b/src/corelib/tools/qspan_p.h @@ -4,6 +4,8 @@ #ifndef QSPAN_P_H #define QSPAN_P_H +#include + // // W A R N I N G // ------------- @@ -15,409 +17,8 @@ // We mean it. // -#include -#include - -#include -#include -#include -#include -#include -#ifdef __cpp_lib_span -#include -#endif -#include - QT_BEGIN_NAMESPACE -// like std::dynamic_extent -namespace q20 { - inline constexpr auto dynamic_extent = std::size_t(-1); -} // namespace q20 - -template class QSpan; - -QT_BEGIN_INCLUDE_NAMESPACE -#ifdef __cpp_lib_span -#ifdef __cpp_lib_concepts -namespace std::ranges { -// Officially, these are defined in , but that is a heavy-hitter header. -// OTOH, must specialize these variable templates, too, so we assume that -// includes some meaningful subset of and just go ahead and use them: -template -constexpr inline bool enable_borrowed_range> = true; -template -constexpr inline bool enable_view> = true; -} // namespace std::ranges -#endif // __cpp_lib_concepts -#endif // __cpp_lib_span -QT_END_INCLUDE_NAMESPACE - -namespace QSpanPrivate { - -template class QSpanBase; - -template -struct is_qspan_helper : std::false_type {}; -template -struct is_qspan_helper> : std::true_type {}; -template -struct is_qspan_helper> : std::true_type {}; -template -using is_qspan = is_qspan_helper>; - -template -struct is_std_span_helper : std::false_type {}; -#ifdef __cpp_lib_span -template -struct is_std_span_helper> : std::true_type {}; -#endif // __cpp_lib_span -template -using is_std_span = is_std_span_helper>; - -template -struct is_std_array_helper : std::false_type {}; -template -struct is_std_array_helper> : std::true_type {}; -template -using is_std_array = is_std_array_helper>; - -template -using is_qualification_conversion = - std::is_convertible; // https://eel.is/c++draft/span.cons#note-1 -template -constexpr inline bool is_qualification_conversion_v = is_qualification_conversion::value; - -// Replacements for std::ranges::XXX(), but only bringing in ADL XXX()s, -// not doing the extra work C++20 requires -template -decltype(auto) adl_begin(Range &&r) { using std::begin; return begin(r); } -template -decltype(auto) adl_data(Range &&r) { using std::data; return data(r); } -template -decltype(auto) adl_size(Range &&r) { using std::size; return size(r); } - -// Replacement for std::ranges::iterator_t (which depends on C++20 std::ranges::begin) -// This one uses adl_begin() instead. -template -using iterator_t = decltype(QSpanPrivate::adl_begin(std::declval())); -template -using range_reference_t = q20::iter_reference_t>; - -template -class QSpanCommon { -protected: - template - using is_compatible_iterator = std::conjunction< - std::is_base_of< - std::random_access_iterator_tag, - typename std::iterator_traits::iterator_category - >, - is_qualification_conversion< - std::remove_reference_t>, - T - > - >; - template - using is_compatible_iterator_and_sentinel = std::conjunction< - is_compatible_iterator, - std::negation> - >; - template // wrap use of SFINAE-unfriendly iterator_t: - struct is_compatible_range_helper : std::false_type {}; - template - struct is_compatible_range_helper>> - : is_compatible_iterator> {}; - template - using is_compatible_range = std::conjunction< - // ### this needs more work, esp. extension to C++20 contiguous iterators - std::negation>, - std::negation>, - std::negation>, - std::negation>>, - is_compatible_range_helper - >; - - // constraints - template - using if_compatible_iterator = std::enable_if_t< - is_compatible_iterator::value - , bool>; - template - using if_compatible_iterator_and_sentinel = std::enable_if_t< - is_compatible_iterator_and_sentinel::value - , bool>; - template - using if_compatible_range = std::enable_if_t::value, bool>; -}; // class QSpanCommon - -template -class QSpanBase : protected QSpanCommon -{ - static_assert(E < size_t{(std::numeric_limits::max)()}, - "QSpan only supports extents that fit into the signed size type (qsizetype)."); - - struct Enabled_t { explicit Enabled_t() = default; }; - static inline constexpr Enabled_t Enable{}; - - template - using if_compatible_array = std::enable_if_t< - N == E && is_qualification_conversion_v - , bool>; - - template - using if_qualification_conversion = std::enable_if_t< - is_qualification_conversion_v - , bool>; -protected: - using Base = QSpanCommon; - - // data members: - T *m_data; - static constexpr qsizetype m_size = qsizetype(E); - - // types and constants: - // (in QSpan only) - - // constructors (need to be public d/t the way ctor inheriting works): -public: - template = true> - Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr} {} - - template = true> - explicit constexpr QSpanBase(It first, qsizetype count) - : m_data{q20::to_address(first)} - { - Q_ASSERT(count == m_size); - } - - template = true> - explicit constexpr QSpanBase(It first, End last) - : QSpanBase(first, last - first) {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t (&arr)[N]) noexcept - : QSpanBase(arr, N) {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(std::array &arr) noexcept - : QSpanBase(arr.data(), N) {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(const std::array &arr) noexcept - : QSpanBase(arr.data(), N) {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(Range &&r) - : QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either) - qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>() - {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(QSpan other) noexcept - : QSpanBase(other.data(), other.size()) - {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(QSpan other) - : QSpanBase(other.data(), other.size()) - {} - -#ifdef __cpp_lib_span - template = true> - Q_IMPLICIT constexpr QSpanBase(std::span other) noexcept - : QSpanBase(other.data(), other.size()) - {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(std::span other) - : QSpanBase(other.data(), other.size()) - {} -#endif // __cpp_lib_span -}; // class QSpanBase (fixed extent) - -template -class QSpanBase : protected QSpanCommon -{ - template - using if_qualification_conversion = std::enable_if_t< - is_qualification_conversion_v - , bool>; -protected: - using Base = QSpanCommon; - - // data members: - T *m_data; - qsizetype m_size; - - // constructors (need to be public d/t the way ctor inheriting works): -public: - Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr}, m_size{0} {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(It first, qsizetype count) - : m_data{q20::to_address(first)}, m_size{count} {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(It first, End last) - : QSpanBase(first, last - first) {} - - template - Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t (&arr)[N]) noexcept - : QSpanBase(arr, N) {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(std::array &arr) noexcept - : QSpanBase(arr.data(), N) {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(const std::array &arr) noexcept - : QSpanBase(arr.data(), N) {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(Range &&r) - : QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either) - qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>() - {} - - template = true> - Q_IMPLICIT constexpr QSpanBase(QSpan other) noexcept - : QSpanBase(other.data(), other.size()) - {} - -#if __cpp_lib_span - template = true> - Q_IMPLICIT constexpr QSpanBase(std::span other) noexcept - : QSpanBase(other.data(), other.size()) - {} -#endif // __cpp_lib_span -}; // class QSpanBase (dynamic extent) - -} // namespace QSpanPrivate - -template -class QSpan -#ifndef Q_QDOC - : private QSpanPrivate::QSpanBase -#endif -{ - using Base = QSpanPrivate::QSpanBase; - Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0, - [[maybe_unused]] qsizetype n = 1) const - { - Q_ASSERT(pos >= 0); - Q_ASSERT(pos <= size()); - Q_ASSERT(n >= 0); - Q_ASSERT(n <= size() - pos); - } - - template - static constexpr bool subspan_always_succeeds_v = N <= E && E != q20::dynamic_extent; -public: - // constants and types - using element_type = T; - using value_type = std::remove_cv_t; - using size_type = qsizetype; // difference to std::span - using difference_type = qptrdiff; // difference to std::span - using pointer = element_type*; - using const_pointer = const element_type*; - using reference = element_type&; - using const_reference = const element_type&; - using iterator = pointer; // implementation-defined choice - using const_iterator = const_pointer; // implementation-defined choice - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - static constexpr std::size_t extent = E; - - // [span.cons], constructors, copy, and assignment - using Base::Base; - - // [span.obs] - [[nodiscard]] constexpr size_type size() const noexcept { return this->m_size; } - [[nodiscard]] constexpr size_type size_bytes() const noexcept { return size() * sizeof(T); } - [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } - - // [span.elem] - [[nodiscard]] constexpr reference operator[](size_type idx) const - { verify(idx); return data()[idx]; } - [[nodiscard]] constexpr reference front() const { verify(); return *data(); } - [[nodiscard]] constexpr reference back() const { verify(); return data()[size() - 1]; } - [[nodiscard]] constexpr pointer data() const noexcept { return this->m_data; } - - // [span.iterators] - [[nodiscard]] constexpr iterator begin() const noexcept { return data(); } - [[nodiscard]] constexpr iterator end() const noexcept { return data() + size(); } - [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); } - [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); } - [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } - [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } - [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } - [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); } - - // [span.sub] - template - [[nodiscard]] constexpr QSpan first() const - noexcept(subspan_always_succeeds_v) - { - static_assert(Count <= E, - "Count cannot be larger than the span's extent."); - verify(0, Count); - return QSpan{data(), Count}; - } - - template - [[nodiscard]] constexpr QSpan last() const - noexcept(subspan_always_succeeds_v) - { - static_assert(Count <= E, - "Count cannot be larger than the span's extent."); - verify(0, Count); - return QSpan{data() + (size() - Count), Count}; - } - - template - [[nodiscard]] constexpr auto subspan() const - noexcept(subspan_always_succeeds_v) - { - static_assert(Offset <= E, - "Offset cannot be larger than the span's extent."); - verify(Offset, 0); - if constexpr (E == q20::dynamic_extent) - return QSpan{data() + Offset, qsizetype(size() - Offset)}; - else - return QSpan{data() + Offset, qsizetype(E - Offset)}; - } - - template - [[nodiscard]] constexpr auto subspan() const - noexcept(subspan_always_succeeds_v) - { return subspan().template first(); } - - [[nodiscard]] constexpr QSpan first(size_type n) const { verify(0, n); return {data(), n}; } - [[nodiscard]] constexpr QSpan last(size_type n) const { verify(0, n); return {data() + (size() - n), n}; } - [[nodiscard]] constexpr QSpan subspan(size_type pos) const { verify(pos, 0); return {data() + pos, size() - pos}; } - [[nodiscard]] constexpr QSpan subspan(size_type pos, size_type n) const { return subspan(pos).first(n); } - - // Qt-compatibility API: - [[nodiscard]] bool isEmpty() const noexcept { return empty(); } - // nullary first()/last() clash with first<>() and last<>(), so they're not provided for QSpan - [[nodiscard]] constexpr QSpan sliced(size_type pos) const { return subspan(pos); } - [[nodiscard]] constexpr QSpan sliced(size_type pos, size_type n) const { return subspan(pos, n); } - -}; // class QSpan - -// [span.deduct] -template -QSpan(It, EndOrSize) -> QSpan>>; -template -QSpan(T (&)[N]) -> QSpan; -template -QSpan(std::array &) -> QSpan; -template -QSpan(const std::array &) -> QSpan; -template -QSpan(R&&) -> QSpan>>; - QT_END_NAMESPACE #endif // QSPAN_P_H diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index b041817d7c3..0048eb5e1ee 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -26,6 +26,7 @@ #include "QtCore/qlist.h" #include "QtCore/qnamespace.h" #include "QtCore/qset.h" +#include #include "QtCore/qstring.h" #include "QtCore/qvarlengtharray.h" @@ -33,7 +34,6 @@ #include "private/qfont_p.h" #include "private/qtextformat_p.h" #include "private/qunicodetools_p.h" -#include "private/qspan_p.h" #ifndef QT_BUILD_COMPAT_LIB #include "private/qtextdocument_p.h" #endif diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp index b97e30642a4..518cfcae57c 100644 --- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp +++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp @@ -16,11 +16,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/tests/auto/corelib/tools/qspan/CMakeLists.txt b/tests/auto/corelib/tools/qspan/CMakeLists.txt index f29179efe4b..d7ea7429649 100644 --- a/tests/auto/corelib/tools/qspan/CMakeLists.txt +++ b/tests/auto/corelib/tools/qspan/CMakeLists.txt @@ -4,6 +4,4 @@ qt_internal_add_test(tst_qspan SOURCES tst_qspan.cpp - LIBRARIES - Qt::CorePrivate ) diff --git a/tests/auto/corelib/tools/qspan/tst_qspan.cpp b/tests/auto/corelib/tools/qspan/tst_qspan.cpp index 35539a7f425..d994484c7b3 100644 --- a/tests/auto/corelib/tools/qspan/tst_qspan.cpp +++ b/tests/auto/corelib/tools/qspan/tst_qspan.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#include +#include #include #include