File indexing completed on 2026-05-05 08:47:29
0001
0002
0003
0004
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 }
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
0059
0060
0061
0062
0063
0064
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
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>,
0105 std::is_pointer<std::decay_t<T>>,
0106 is_compatible_char<T>,
0107 std::is_same<q20::remove_cvref_t<T>, QByteArray>,
0108 std::is_same<q20::remove_cvref_t<T>, QString>
0109 >>,
0110
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
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
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}); }
0157 static QChar toQChar(QChar ch) noexcept { return ch; }
0158 static QChar toQChar(QLatin1Char ch) noexcept { return ch; }
0159
0160 struct QCharContainer {
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)
0169 return QAnyStringView{&ch, 1, size_t{Tag::Latin1}};
0170 else
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} {}
0206 #endif
0207
0208
0209 inline QAnyStringView(const QByteArray &str) noexcept;
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
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
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
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;
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
0318
0319 [[nodiscard]] constexpr QChar front() const;
0320 [[nodiscard]] constexpr QChar back() const;
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
0328 return QtPrivate::MaxAllocSize / charSize() - 1;
0329 }
0330
0331
0332
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