Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-05 08:47:29

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