Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-13 09:05:55

0001 // Copyright (C) 2022 The Qt Company Ltd.
0002 // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
0003 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0004 #ifndef QANYSTRINGVIEW_H
0005 #define QANYSTRINGVIEW_H
0006 
0007 #include <QtCore/qcompare.h>
0008 #include <QtCore/qcontainerfwd.h>
0009 #include <QtCore/qlatin1stringview.h>
0010 #include <QtCore/qstringview.h>
0011 #include <QtCore/qutf8stringview.h>
0012 
0013 #include <QtCore/q20type_traits.h>
0014 #include <limits>
0015 
0016 class tst_QAnyStringView;
0017 
0018 QT_BEGIN_NAMESPACE
0019 
0020 namespace QtPrivate {
0021 
0022 template <typename Tag, typename Result>
0023 struct wrapped { using type = Result; };
0024 
0025 template <typename Tag, typename Result>
0026 using wrapped_t = typename wrapped<Tag, Result>::type;
0027 
0028 } // namespace QtPrivate
0029 
0030 class QAnyStringView
0031 {
0032 public:
0033     typedef qptrdiff difference_type;
0034     typedef qsizetype size_type;
0035 private:
0036     static constexpr size_t SizeMask = (std::numeric_limits<size_t>::max)() / 4;
0037 #if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED)
0038     static constexpr int SizeShift = 2;
0039     static constexpr size_t Latin1Flag = 1;
0040 #else
0041     static constexpr int SizeShift = 0;
0042     static constexpr size_t Latin1Flag = SizeMask + 1;
0043 #endif
0044     static constexpr size_t TwoByteCodePointFlag = Latin1Flag << 1;
0045     static constexpr size_t TypeMask = ~(SizeMask << SizeShift);
0046     static_assert(TypeMask == (Latin1Flag|TwoByteCodePointFlag));
0047 
0048     // Tag bits
0049     //  0  0   Utf8
0050     //  0  1   Latin1
0051     //  1  0   Utf16
0052     //  1  1   Unused
0053     //  ^  ^ latin1
0054     //  | sizeof code-point == 2
0055     enum Tag : size_t {
0056         Utf8     = 0,
0057         Latin1   = Latin1Flag,
0058         Utf16    = TwoByteCodePointFlag,
0059         Unused   = TypeMask,
0060     };
0061 
0062     template <typename Char>
0063     using is_compatible_char = std::disjunction<
0064         QtPrivate::IsCompatibleCharType<Char>,
0065         QtPrivate::IsCompatibleChar8Type<Char>
0066     >;
0067 
0068     template <typename Char>
0069     using if_compatible_char = std::enable_if_t<is_compatible_char<Char>::value, bool>;
0070 
0071     template <typename Pointer>
0072     using if_compatible_pointer = std::enable_if_t<std::disjunction_v<
0073         QtPrivate::IsCompatiblePointer<Pointer>,
0074         QtPrivate::IsCompatiblePointer8<Pointer>
0075     >, bool>;
0076 
0077 
0078     template <typename T>
0079     using if_compatible_container = std::enable_if_t<std::disjunction_v<
0080         QtPrivate::IsContainerCompatibleWithQStringView<T>,
0081         QtPrivate::IsContainerCompatibleWithQUtf8StringView<T>
0082     >, bool>;
0083 
0084     template <typename QStringOrQByteArray, typename T>
0085     using if_convertible_to = std::enable_if_t<std::conjunction_v<
0086         // need to exclude a bunch of stuff, because we take by universal reference:
0087         std::negation<std::disjunction<
0088             std::is_same<q20::remove_cvref_t<T>, QAnyStringView::Tag>,
0089             std::is_same<q20::remove_cvref_t<T>, QAnyStringView>, // don't make a copy/move ctor
0090             std::is_pointer<std::decay_t<T>>, // const char*, etc
0091             is_compatible_char<T>, // don't create a QString/QByteArray, we have a ctor
0092             std::is_same<q20::remove_cvref_t<T>, QByteArray>,
0093             std::is_same<q20::remove_cvref_t<T>, QString>
0094         >>,
0095         // this is what we're really after:
0096         std::is_convertible<T, QStringOrQByteArray>
0097     >, bool>;
0098 
0099     // confirm we don't make an accidental copy constructor:
0100     static_assert(QtPrivate::IsContainerCompatibleWithQStringView<QAnyStringView>::value == false);
0101     static_assert(QtPrivate::IsContainerCompatibleWithQUtf8StringView<QAnyStringView>::value == false);
0102 
0103     template<typename Char>
0104     static constexpr bool isAsciiOnlyCharsAtCompileTime(Char *str, qsizetype sz) noexcept
0105     {
0106         // do not perform check if not at compile time
0107         if (!q20::is_constant_evaluated())
0108             return false;
0109         if constexpr (sizeof(Char) != sizeof(char)) {
0110             Q_UNUSED(str);
0111             Q_UNUSED(sz);
0112             return false;
0113         } else {
0114             for (qsizetype i = 0; i < sz; ++i) {
0115                 if (uchar(str[i]) > 0x7f)
0116                     return false;
0117             }
0118             return true;
0119         }
0120     }
0121 
0122     template<typename Char>
0123     static constexpr std::size_t encodeType(const Char *str, qsizetype sz) noexcept
0124     {
0125         // Utf16 if 16 bit, Latin1 if ASCII, else Utf8
0126         Q_ASSERT(sz >= 0);
0127         Q_ASSERT(sz <= qsizetype(SizeMask));
0128         Q_ASSERT(str || !sz);
0129         return (std::size_t(sz) << SizeShift)
0130                 | uint(sizeof(Char) == sizeof(char16_t)) * Tag::Utf16
0131                 | uint(isAsciiOnlyCharsAtCompileTime(str, sz)) * Tag::Latin1;
0132     }
0133 
0134     template <typename Char>
0135     static constexpr qsizetype lengthHelperPointer(const Char *str) noexcept
0136     {
0137         if (q20::is_constant_evaluated())
0138             return QtPrivate::lengthHelperPointer(str);
0139         if constexpr (sizeof(Char) == sizeof(char16_t))
0140             return QtPrivate::qustrlen(reinterpret_cast<const char16_t*>(str));
0141         else
0142             return qsizetype(strlen(reinterpret_cast<const char*>(str)));
0143     }
0144 
0145     static QChar toQChar(char ch) noexcept { return toQChar(QLatin1Char{ch}); } // we don't handle UTF-8 multibytes
0146     static QChar toQChar(QChar ch) noexcept { return ch; }
0147     static QChar toQChar(QLatin1Char ch) noexcept { return ch; }
0148 
0149     struct QCharContainer { // private, so users can't pass their own
0150         explicit QCharContainer() = default;
0151         QChar ch;
0152     };
0153 
0154     template <typename Char>
0155     static constexpr QAnyStringView fromCharInternal(const Char &ch) noexcept
0156     {
0157         if constexpr (sizeof ch == 1) // even char8_t is Latin-1 as single octet
0158             return QAnyStringView{&ch, 1, size_t{Tag::Latin1}};
0159         else // sizeof ch == 2
0160             return {&ch, 1};
0161     }
0162 
0163     explicit constexpr QAnyStringView(const void *d, qsizetype n, std::size_t sizeAndType) noexcept
0164         : m_data{d}, m_size{std::size_t(n) | (sizeAndType & TypeMask)} {}
0165 public:
0166     constexpr QAnyStringView() noexcept
0167         : m_data{nullptr}, m_size{0} {}
0168     constexpr QAnyStringView(std::nullptr_t) noexcept
0169         : QAnyStringView() {}
0170 
0171     template <typename Char, if_compatible_char<Char> = true>
0172     constexpr QAnyStringView(const Char *str, qsizetype len)
0173         : m_data{str}, m_size{encodeType<Char>(str, len)}
0174     {
0175     }
0176 
0177     template <typename Char, if_compatible_char<Char> = true>
0178     constexpr QAnyStringView(const Char *f, const Char *l)
0179         : QAnyStringView(f, l - f) {}
0180 
0181 #ifdef Q_QDOC
0182     template <typename Char, size_t N>
0183     constexpr QAnyStringView(const Char (&array)[N]) noexcept;
0184 
0185     template <typename Char>
0186     constexpr QAnyStringView(const Char *str) noexcept;
0187 #else
0188     template <typename Pointer, if_compatible_pointer<Pointer> = true>
0189     constexpr QAnyStringView(const Pointer &str) noexcept
0190         : QAnyStringView{str, str ? lengthHelperPointer(str) : 0} {}
0191 
0192     template <typename Char, if_compatible_char<Char> = true>
0193     constexpr QAnyStringView(const Char (&str)[]) noexcept
0194         : QAnyStringView{&*str} {} // decay to pointer
0195 #endif
0196 
0197     // defined in qstring.h
0198     inline QAnyStringView(const QByteArray &str) noexcept; // TODO: Should we have this at all? Remove?
0199     inline QAnyStringView(const QString &str) noexcept;
0200     inline constexpr QAnyStringView(QLatin1StringView str) noexcept;
0201 
0202     template <typename Container, if_compatible_container<Container> = true>
0203     constexpr Q_ALWAYS_INLINE QAnyStringView(const Container &c) noexcept
0204         : QAnyStringView(std::data(c), QtPrivate::lengthHelperContainer(c)) {}
0205 
0206     template <typename Container, if_convertible_to<QString, Container> = true>
0207     constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t<Container, QString> &&capacity = {})
0208             //noexcept(std::is_nothrow_constructible_v<QString, Container>)
0209         : QAnyStringView(capacity = std::forward<Container>(c)) {}
0210 
0211     template <typename Container, if_convertible_to<QByteArray, Container> = true>
0212     constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t<Container, QByteArray> &&capacity = {})
0213             //noexcept(std::is_nothrow_constructible_v<QByteArray, Container>)
0214         : QAnyStringView(capacity = std::forward<Container>(c)) {}
0215 
0216     template <typename Char, if_compatible_char<Char> = true>
0217     constexpr QAnyStringView(const Char &c) noexcept
0218         : QAnyStringView{fromCharInternal(c)} {}
0219     template <typename Char, if_convertible_to<QChar, Char> = true>
0220     constexpr QAnyStringView(Char ch, QCharContainer &&capacity = QCharContainer()) noexcept
0221         : QAnyStringView{&(capacity.ch = ch), 1} {}
0222     template <typename Char, typename Container = decltype(QChar::fromUcs4(U'x')),
0223               std::enable_if_t<std::is_same_v<Char, char32_t>, bool> = true>
0224     constexpr QAnyStringView(Char c, Container &&capacity = {}) noexcept
0225         : QAnyStringView(capacity = QChar::fromUcs4(c)) {}
0226 
0227     constexpr QAnyStringView(QStringView v) noexcept
0228         : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {}
0229 
0230     template <bool UseChar8T>
0231     constexpr QAnyStringView(QBasicUtf8StringView<UseChar8T> v) noexcept
0232         : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {}
0233 
0234     template <typename Char, size_t Size, if_compatible_char<Char> = true>
0235     [[nodiscard]] constexpr static QAnyStringView fromArray(const Char (&string)[Size]) noexcept
0236     { return QAnyStringView(string, Size); }
0237 
0238     // defined in qstring.h:
0239     template <typename Visitor>
0240     inline constexpr decltype(auto) visit(Visitor &&v) const;
0241 
0242     [[nodiscard]]
0243     constexpr QAnyStringView mid(qsizetype pos, qsizetype n = -1) const
0244     {
0245         using namespace QtPrivate;
0246         auto result = QContainerImplHelper::mid(size(), &pos, &n);
0247         return result == QContainerImplHelper::Null ? QAnyStringView() : sliced(pos, n);
0248     }
0249     [[nodiscard]]
0250     constexpr QAnyStringView left(qsizetype n) const
0251     {
0252         if (size_t(n) >= size_t(size()))
0253             n = size();
0254         return sliced(0, n);
0255     }
0256     [[nodiscard]]
0257     constexpr QAnyStringView right(qsizetype n) const
0258     {
0259         if (size_t(n) >= size_t(size()))
0260             n = size();
0261         return sliced(size() - n, n);
0262     }
0263 
0264     [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos) const
0265     { verify(pos, 0); auto r = *this; r.advanceData(pos); r.setSize(size() - pos); return r; }
0266     [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos, qsizetype n) const
0267     { verify(pos, n); auto r = *this; r.advanceData(pos); r.setSize(n); return r; }
0268     [[nodiscard]] constexpr QAnyStringView first(qsizetype n) const
0269     { verify(0, n); return sliced(0, n); }
0270     [[nodiscard]] constexpr QAnyStringView last(qsizetype n) const
0271     { verify(0, n); return sliced(size() - n, n); }
0272     [[nodiscard]] constexpr QAnyStringView chopped(qsizetype n) const
0273     { verify(0, n); return sliced(0, size() - n); }
0274 
0275     constexpr QAnyStringView &slice(qsizetype pos)
0276     { *this = sliced(pos); return *this; }
0277     constexpr QAnyStringView &slice(qsizetype pos, qsizetype n)
0278     { *this = sliced(pos, n); return *this; }
0279 
0280     constexpr void truncate(qsizetype n)
0281     { verify(0, n); setSize(n); }
0282     constexpr void chop(qsizetype n)
0283     { verify(0, n); setSize(size() - n); }
0284 
0285     template <typename...Args>
0286     [[nodiscard]] inline QString arg(Args &&...args) const;
0287 
0288     [[nodiscard]] inline QString toString() const; // defined in qstring.h
0289 
0290     [[nodiscard]] constexpr qsizetype size() const noexcept
0291     { return qsizetype((m_size >> SizeShift) & SizeMask); }
0292     [[nodiscard]] constexpr const void *data() const noexcept { return m_data; }
0293 
0294     [[nodiscard]] Q_CORE_EXPORT static int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
0295     [[nodiscard]] Q_CORE_EXPORT static bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept;
0296 
0297     static constexpr inline bool detects_US_ASCII_at_compile_time =
0298 #ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
0299             true
0300 #else
0301             false
0302 #endif
0303             ;
0304 
0305     //
0306     // STL compatibility API:
0307     //
0308     [[nodiscard]] constexpr QChar front() const; // NOT noexcept!
0309     [[nodiscard]] constexpr QChar back() const; // NOT noexcept!
0310     [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
0311     [[nodiscard]] constexpr qsizetype size_bytes() const noexcept
0312     { return size() * charSize(); }
0313 
0314     [[nodiscard]] constexpr qsizetype max_size() const noexcept
0315     {
0316         // -1 to deal with the pointer one-past-the-end;
0317         return QtPrivate::MaxAllocSize / charSize() - 1;
0318     }
0319 
0320     //
0321     // Qt compatibility API:
0322     //
0323     [[nodiscard]] constexpr bool isNull() const noexcept { return !m_data; }
0324     [[nodiscard]] constexpr bool isEmpty() const noexcept { return empty(); }
0325     [[nodiscard]] constexpr qsizetype length() const noexcept
0326     { return size(); }
0327 
0328 private:
0329     friend bool comparesEqual(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
0330     { return QAnyStringView::equal(lhs, rhs); }
0331     friend Qt::strong_ordering
0332     compareThreeWay(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
0333     {
0334         const int res = QAnyStringView::compare(lhs, rhs);
0335         return Qt::compareThreeWay(res, 0);
0336     }
0337     Q_DECLARE_STRONGLY_ORDERED(QAnyStringView)
0338 
0339 #ifndef QT_NO_DEBUG_STREAM
0340     Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s);
0341 #endif
0342 
0343     [[nodiscard]] constexpr Tag tag() const noexcept { return Tag{m_size & TypeMask}; }
0344     [[nodiscard]] constexpr bool isUtf16() const noexcept { return tag() == Tag::Utf16; }
0345     [[nodiscard]] constexpr bool isUtf8() const noexcept { return tag() == Tag::Utf8; }
0346     [[nodiscard]] constexpr bool isLatin1() const noexcept { return tag() == Tag::Latin1; }
0347     [[nodiscard]] constexpr QStringView asStringView() const
0348     { return Q_ASSERT(isUtf16()), QStringView{m_data_utf16, size()}; }
0349     [[nodiscard]] constexpr q_no_char8_t::QUtf8StringView asUtf8StringView() const
0350     { return Q_ASSERT(isUtf8()), q_no_char8_t::QUtf8StringView{m_data_utf8, size()}; }
0351     [[nodiscard]] inline constexpr QLatin1StringView asLatin1StringView() const;
0352     [[nodiscard]] constexpr size_t charSize() const noexcept { return isUtf16() ? 2 : 1; }
0353     constexpr void setSize(qsizetype sz) noexcept { m_size = size_t(sz) | tag(); }
0354     constexpr void advanceData(qsizetype delta) noexcept
0355     { m_data_utf8 += delta * charSize(); }
0356     Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
0357                                           [[maybe_unused]] qsizetype n = 1) const
0358     {
0359         Q_ASSERT(pos >= 0);
0360         Q_ASSERT(pos <= size());
0361         Q_ASSERT(n >= 0);
0362         Q_ASSERT(n <= size() - pos);
0363     }
0364     union {
0365         const void *m_data;
0366         const char *m_data_utf8;
0367         const char16_t *m_data_utf16;
0368     };
0369     size_t m_size;
0370     friend class ::tst_QAnyStringView;
0371 };
0372 Q_DECLARE_TYPEINFO(QAnyStringView, Q_PRIMITIVE_TYPE);
0373 
0374 template <typename QStringLike, std::enable_if_t<std::disjunction_v<
0375         std::is_same<QStringLike, QString>,
0376         std::is_same<QStringLike, QByteArray>
0377     >, bool> = true>
0378 [[nodiscard]] inline QAnyStringView qToAnyStringViewIgnoringNull(const QStringLike &s) noexcept
0379 { return QAnyStringView(s.begin(), s.size()); }
0380 
0381 QT_END_NAMESPACE
0382 
0383 #endif /* QANYSTRINGVIEW_H */