File indexing completed on 2025-09-13 09:05:55
0001
0002
0003
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 }
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
0049
0050
0051
0052
0053
0054
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
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>,
0090 std::is_pointer<std::decay_t<T>>,
0091 is_compatible_char<T>,
0092 std::is_same<q20::remove_cvref_t<T>, QByteArray>,
0093 std::is_same<q20::remove_cvref_t<T>, QString>
0094 >>,
0095
0096 std::is_convertible<T, QStringOrQByteArray>
0097 >, bool>;
0098
0099
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
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
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}); }
0146 static QChar toQChar(QChar ch) noexcept { return ch; }
0147 static QChar toQChar(QLatin1Char ch) noexcept { return ch; }
0148
0149 struct QCharContainer {
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)
0158 return QAnyStringView{&ch, 1, size_t{Tag::Latin1}};
0159 else
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} {}
0195 #endif
0196
0197
0198 inline QAnyStringView(const QByteArray &str) noexcept;
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
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
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
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;
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
0307
0308 [[nodiscard]] constexpr QChar front() const;
0309 [[nodiscard]] constexpr QChar back() const;
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
0317 return QtPrivate::MaxAllocSize / charSize() - 1;
0318 }
0319
0320
0321
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