summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qanystringview.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/text/qanystringview.h')
-rw-r--r--src/corelib/text/qanystringview.h294
1 files changed, 172 insertions, 122 deletions
diff --git a/src/corelib/text/qanystringview.h b/src/corelib/text/qanystringview.h
index 774651cb6a..01efd83743 100644
--- a/src/corelib/text/qanystringview.h
+++ b/src/corelib/text/qanystringview.h
@@ -1,56 +1,33 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANYSTRINGVIEW_H
#define QANYSTRINGVIEW_H
+#include <QtCore/qcompare.h>
+#include <QtCore/qlatin1stringview.h>
#include <QtCore/qstringview.h>
#include <QtCore/qutf8stringview.h>
#ifdef __cpp_impl_three_way_comparison
#include <compare>
#endif
+#include <QtCore/q20type_traits.h>
#include <limits>
+class tst_QAnyStringView;
+
QT_BEGIN_NAMESPACE
-template <typename, typename> class QStringBuilder;
-template <typename> struct QConcatenable;
+namespace QtPrivate {
+
+template <typename Tag, typename Result>
+struct wrapped { using type = Result; };
+
+template <typename Tag, typename Result>
+using wrapped_t = typename wrapped<Tag, Result>::type;
+
+} // namespace QtPrivate
class QAnyStringView
{
@@ -58,6 +35,32 @@ public:
typedef qptrdiff difference_type;
typedef qsizetype size_type;
private:
+ static constexpr size_t SizeMask = (std::numeric_limits<size_t>::max)() / 4;
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED)
+ static constexpr int SizeShift = 2;
+ static constexpr size_t Latin1Flag = 1;
+#else
+ static constexpr int SizeShift = 0;
+ static constexpr size_t Latin1Flag = SizeMask + 1;
+#endif
+ static constexpr size_t TwoByteCodePointFlag = Latin1Flag << 1;
+ static constexpr size_t TypeMask = ~(SizeMask << SizeShift);
+ static_assert(TypeMask == (Latin1Flag|TwoByteCodePointFlag));
+
+ // Tag bits
+ // 0 0 Utf8
+ // 0 1 Latin1
+ // 1 0 Utf16
+ // 1 1 Unused
+ // ^ ^ latin1
+ // | sizeof code-point == 2
+ enum Tag : size_t {
+ Utf8 = 0,
+ Latin1 = Latin1Flag,
+ Utf16 = TwoByteCodePointFlag,
+ Unused = TypeMask,
+ };
+
template <typename Char>
using if_compatible_char = std::enable_if_t<std::disjunction_v<
QtPrivate::IsCompatibleCharType<Char>,
@@ -77,51 +80,66 @@ private:
QtPrivate::IsContainerCompatibleWithQUtf8StringView<T>
>, bool>;
+ template <typename QStringOrQByteArray, typename T>
+ using if_convertible_to = std::enable_if_t<std::conjunction_v<
+ // need to exclude a bunch of stuff, because we take by universal reference:
+ std::negation<std::disjunction<
+ std::is_same<q20::remove_cvref_t<T>, QAnyStringView::Tag>,
+ std::is_same<q20::remove_cvref_t<T>, QAnyStringView>, // don't make a copy/move ctor
+ std::is_pointer<std::decay_t<T>>, // const char*, etc
+ std::is_same<q20::remove_cvref_t<T>, QByteArray>,
+ std::is_same<q20::remove_cvref_t<T>, QString>
+ >>,
+ // this is what we're really after:
+ std::is_convertible<T, QStringOrQByteArray>
+ >, bool>;
+
// confirm we don't make an accidental copy constructor:
static_assert(QtPrivate::IsContainerCompatibleWithQStringView<QAnyStringView>::value == false);
static_assert(QtPrivate::IsContainerCompatibleWithQUtf8StringView<QAnyStringView>::value == false);
- template <typename Char>
- static constexpr std::size_t encodeType(qsizetype sz) noexcept
+ template<typename Char>
+ static constexpr bool isAsciiOnlyCharsAtCompileTime(Char *str, qsizetype sz) noexcept
+ {
+ // do not perform check if not at compile time
+ if (!q20::is_constant_evaluated())
+ return false;
+ if constexpr (sizeof(Char) != sizeof(char)) {
+ Q_UNUSED(str);
+ Q_UNUSED(sz);
+ return false;
+ } else {
+ for (qsizetype i = 0; i < sz; ++i) {
+ if (uchar(str[i]) > 0x7f)
+ return false;
+ }
+ return true;
+ }
+ }
+
+ template<typename Char>
+ static constexpr std::size_t encodeType(const Char *str, qsizetype sz) noexcept
{
- // only deals with Utf8 and Utf16 - there's only one way to create
- // a Latin1 string, and that ctor deals with the tag itself
+ // Utf16 if 16 bit, Latin1 if ASCII, else Utf8
Q_ASSERT(sz >= 0);
Q_ASSERT(sz <= qsizetype(SizeMask));
- return std::size_t(sz) | uint(sizeof(Char) == sizeof(char16_t)) * Tag::Utf16;
+ Q_ASSERT(str || !sz);
+ return (std::size_t(sz) << SizeShift)
+ | uint(sizeof(Char) == sizeof(char16_t)) * Tag::Utf16
+ | uint(isAsciiOnlyCharsAtCompileTime(str, sz)) * Tag::Latin1;
}
template <typename Char>
- static qsizetype lengthHelperPointer(const Char *str) noexcept
+ static constexpr qsizetype lengthHelperPointer(const Char *str) noexcept
{
-#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL)
- if (__builtin_constant_p(*str)) {
- qsizetype result = 0;
- while (*str++ != u'\0')
- ++result;
- return result;
- }
-#endif
+ if (q20::is_constant_evaluated())
+ return qsizetype(std::char_traits<Char>::length(str));
if constexpr (sizeof(Char) == sizeof(char16_t))
return QtPrivate::qustrlen(reinterpret_cast<const char16_t*>(str));
else
return qsizetype(strlen(reinterpret_cast<const char*>(str)));
}
- template <typename Container>
- static constexpr qsizetype lengthHelperContainer(const Container &c) noexcept
- {
- return qsizetype(std::size(c));
- }
-
- template <typename Char, size_t N>
- static constexpr qsizetype lengthHelperContainer(const Char (&str)[N]) noexcept
- {
- const auto it = std::char_traits<Char>::find(str, N, Char(0));
- const auto end = it ? it : std::next(str, N);
- return qsizetype(std::distance(str, end));
- }
-
static QChar toQChar(char ch) noexcept { return toQChar(QLatin1Char{ch}); } // we don't handle UTF-8 multibytes
static QChar toQChar(QChar ch) noexcept { return ch; }
static QChar toQChar(QLatin1Char ch) noexcept { return ch; }
@@ -136,14 +154,15 @@ public:
template <typename Char, if_compatible_char<Char> = true>
constexpr QAnyStringView(const Char *str, qsizetype len)
- : m_data{str},
- m_size{encodeType<Char>((Q_ASSERT(len >= 0), Q_ASSERT(str || !len), len))} {}
+ : m_data{str}, m_size{encodeType<Char>(str, len)}
+ {
+ }
template <typename Char, if_compatible_char<Char> = true>
constexpr QAnyStringView(const Char *f, const Char *l)
: QAnyStringView(f, l - f) {}
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
template <typename Char, size_t N>
constexpr QAnyStringView(const Char (&array)[N]) noexcept;
@@ -159,16 +178,21 @@ public:
// defined in qstring.h
inline QAnyStringView(const QByteArray &str) noexcept; // TODO: Should we have this at all? Remove?
inline QAnyStringView(const QString &str) noexcept;
- inline constexpr QAnyStringView(QLatin1String str) noexcept;
-
- // defined in qstringbuilder.h
- template <typename A, typename B>
- inline QAnyStringView(const QStringBuilder<A, B> &expr,
- typename QConcatenable<QStringBuilder<A, B>>::ConvertTo &&capacity = {});
+ inline constexpr QAnyStringView(QLatin1StringView str) noexcept;
template <typename Container, if_compatible_container<Container> = true>
- constexpr QAnyStringView(const Container &c) noexcept
- : QAnyStringView(std::data(c), lengthHelperContainer(c)) {}
+ constexpr Q_ALWAYS_INLINE QAnyStringView(const Container &c) noexcept
+ : QAnyStringView(std::data(c), QtPrivate::lengthHelperContainer(c)) {}
+
+ template <typename Container, if_convertible_to<QString, Container> = true>
+ constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t<Container, QString> &&capacity = {})
+ //noexcept(std::is_nothrow_constructible_v<QString, Container>)
+ : QAnyStringView(capacity = std::forward<Container>(c)) {}
+
+ template <typename Container, if_convertible_to<QByteArray, Container> = true>
+ constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t<Container, QByteArray> &&capacity = {})
+ //noexcept(std::is_nothrow_constructible_v<QByteArray, Container>)
+ : QAnyStringView(capacity = std::forward<Container>(c)) {}
template <typename Char, if_compatible_char<Char> = true>
constexpr QAnyStringView(const Char &c) noexcept
@@ -182,11 +206,11 @@ public:
: QAnyStringView(capacity = QChar::fromUcs4(c)) {}
constexpr QAnyStringView(QStringView v) noexcept
- : QAnyStringView(std::data(v), lengthHelperContainer(v)) {}
+ : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {}
template <bool UseChar8T>
constexpr QAnyStringView(QBasicUtf8StringView<UseChar8T> v) noexcept
- : QAnyStringView(std::data(v), lengthHelperContainer(v)) {}
+ : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {}
template <typename Char, size_t Size, if_compatible_char<Char> = true>
[[nodiscard]] constexpr static QAnyStringView fromArray(const Char (&string)[Size]) noexcept
@@ -196,14 +220,62 @@ public:
template <typename Visitor>
inline constexpr decltype(auto) visit(Visitor &&v) const;
+ [[nodiscard]]
+ constexpr QAnyStringView mid(qsizetype pos, qsizetype n = -1) const
+ {
+ using namespace QtPrivate;
+ auto result = QContainerImplHelper::mid(size(), &pos, &n);
+ return result == QContainerImplHelper::Null ? QAnyStringView() : sliced(pos, n);
+ }
+ [[nodiscard]]
+ constexpr QAnyStringView left(qsizetype n) const
+ {
+ if (size_t(n) >= size_t(size()))
+ n = size();
+ return sliced(0, n);
+ }
+ [[nodiscard]]
+ constexpr QAnyStringView right(qsizetype n) const
+ {
+ if (size_t(n) >= size_t(size()))
+ n = size();
+ return sliced(size() - n, n);
+ }
+
+ [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos) const
+ { verify(pos, 0); auto r = *this; r.advanceData(pos); r.setSize(size() - pos); return r; }
+ [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos, qsizetype n) const
+ { verify(pos, n); auto r = *this; r.advanceData(pos); r.setSize(n); return r; }
+ [[nodiscard]] constexpr QAnyStringView first(qsizetype n) const
+ { verify(0, n); return sliced(0, n); }
+ [[nodiscard]] constexpr QAnyStringView last(qsizetype n) const
+ { verify(0, n); return sliced(size() - n, n); }
+ [[nodiscard]] constexpr QAnyStringView chopped(qsizetype n) const
+ { verify(0, n); return sliced(0, size() - n); }
+
+ constexpr void truncate(qsizetype n)
+ { verify(0, n); setSize(n); }
+ constexpr void chop(qsizetype n)
+ { verify(0, n); setSize(size() - n); }
+
+
[[nodiscard]] inline QString toString() const; // defined in qstring.h
- [[nodiscard]] constexpr qsizetype size() const noexcept { return qsizetype(m_size & SizeMask); }
+ [[nodiscard]] constexpr qsizetype size() const noexcept
+ { return qsizetype((m_size >> SizeShift) & SizeMask); }
[[nodiscard]] constexpr const void *data() const noexcept { return m_data; }
[[nodiscard]] Q_CORE_EXPORT static int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT static bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept;
+ static constexpr inline bool detects_US_ASCII_at_compile_time =
+#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
+ true
+#else
+ false
+#endif
+ ;
+
//
// STL compatibility API:
//
@@ -222,47 +294,20 @@ public:
{ return size(); }
private:
- [[nodiscard]] friend inline bool operator==(QAnyStringView lhs, QAnyStringView rhs) noexcept
+ friend bool comparesEqual(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
{ return QAnyStringView::equal(lhs, rhs); }
- [[nodiscard]] friend inline bool operator!=(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return !QAnyStringView::equal(lhs, rhs); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
+ {
+ const int res = QAnyStringView::compare(lhs, rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QAnyStringView)
-#if defined(__cpp_impl_three_way_comparison) && !defined(Q_QDOC)
- [[nodiscard]] friend inline auto operator<=>(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) <=> 0; }
-#else
- [[nodiscard]] friend inline bool operator<=(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) <= 0; }
- [[nodiscard]] friend inline bool operator>=(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) >= 0; }
- [[nodiscard]] friend inline bool operator<(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) < 0; }
- [[nodiscard]] friend inline bool operator>(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) > 0; }
+#ifndef QT_NO_DEBUG_STREAM
+ Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s);
#endif
- // TODO: Optimize by inverting and storing the flags in the low bits and
- // the size in the high.
- static_assert(std::is_same_v<std::size_t, size_t>);
- static_assert(sizeof(size_t) == sizeof(qsizetype));
- static constexpr size_t SizeMask = (std::numeric_limits<size_t>::max)() / 4;
- static constexpr size_t Latin1Flag = SizeMask + 1;
- static constexpr size_t TwoByteCodePointFlag = Latin1Flag << 1;
- static constexpr size_t TypeMask = (std::numeric_limits<size_t>::max)() & ~SizeMask;
- static_assert(TypeMask == (Latin1Flag|TwoByteCodePointFlag));
- // HI HI LO LO ...
- // 0 0 SZ SZ Utf8
- // 0 1 SZ SZ Latin1
- // 1 0 SZ SZ Utf16
- // 1 1 SZ SZ Unused
- // ^ ^ latin1
- // | sizeof code-point == 2
- enum Tag : size_t {
- Utf8 = 0,
- Latin1 = Latin1Flag,
- Utf16 = TwoByteCodePointFlag,
- Unused = TypeMask,
- };
[[nodiscard]] constexpr Tag tag() const noexcept { return Tag{m_size & TypeMask}; }
[[nodiscard]] constexpr bool isUtf16() const noexcept { return tag() == Tag::Utf16; }
[[nodiscard]] constexpr bool isUtf8() const noexcept { return tag() == Tag::Utf8; }
@@ -271,9 +316,13 @@ private:
{ return Q_ASSERT(isUtf16()), QStringView{m_data_utf16, size()}; }
[[nodiscard]] constexpr q_no_char8_t::QUtf8StringView asUtf8StringView() const
{ return Q_ASSERT(isUtf8()), q_no_char8_t::QUtf8StringView{m_data_utf8, size()}; }
- [[nodiscard]] inline constexpr QLatin1String asLatin1StringView() const;
+ [[nodiscard]] inline constexpr QLatin1StringView asLatin1StringView() const;
[[nodiscard]] constexpr size_t charSize() const noexcept { return isUtf16() ? 2 : 1; }
- Q_ALWAYS_INLINE constexpr void verify(qsizetype pos, qsizetype n = 0) const
+ constexpr void setSize(qsizetype sz) noexcept { m_size = size_t(sz) | tag(); }
+ constexpr void advanceData(qsizetype delta) noexcept
+ { m_data_utf8 += delta * charSize(); }
+ 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());
@@ -286,6 +335,7 @@ private:
const char16_t *m_data_utf16;
};
size_t m_size;
+ friend class ::tst_QAnyStringView;
};
Q_DECLARE_TYPEINFO(QAnyStringView, Q_PRIMITIVE_TYPE);
@@ -294,7 +344,7 @@ template <typename QStringLike, std::enable_if_t<std::disjunction_v<
std::is_same<QStringLike, QByteArray>
>, bool> = true>
[[nodiscard]] inline QAnyStringView qToAnyStringViewIgnoringNull(const QStringLike &s) noexcept
-{ return QAnyStringView(s.data(), s.size()); }
+{ return QAnyStringView(s.begin(), s.size()); }
QT_END_NAMESPACE