File indexing completed on 2025-09-17 09:09:34
0001
0002
0003 #ifndef QSTRINGTOKENIZER_H
0004 #define QSTRINGTOKENIZER_H
0005
0006 #include <QtCore/qnamespace.h>
0007 #include <QtCore/qcontainerfwd.h>
0008 #include <iterator>
0009
0010 QT_BEGIN_NAMESPACE
0011
0012 template <typename, typename> class QStringBuilder;
0013
0014 class QStringTokenizerBaseBase
0015 {
0016 protected:
0017 ~QStringTokenizerBaseBase() = default;
0018 constexpr QStringTokenizerBaseBase(Qt::SplitBehavior sb, Qt::CaseSensitivity cs) noexcept
0019 : m_sb{sb}, m_cs{cs} {}
0020
0021 struct tokenizer_state {
0022 qsizetype start, end, extra;
0023 friend constexpr bool operator==(tokenizer_state lhs, tokenizer_state rhs) noexcept
0024 { return lhs.start == rhs.start && lhs.end == rhs.end && lhs.extra == rhs.extra; }
0025 friend constexpr bool operator!=(tokenizer_state lhs, tokenizer_state rhs) noexcept
0026 { return !operator==(lhs, rhs); }
0027 };
0028
0029 Qt::SplitBehavior m_sb;
0030 Qt::CaseSensitivity m_cs;
0031 };
0032
0033 template <typename Haystack, typename Needle>
0034 class QStringTokenizerBase : protected QStringTokenizerBaseBase
0035 {
0036 struct next_result {
0037 Haystack value;
0038 bool ok;
0039 tokenizer_state state;
0040 };
0041 inline next_result next(tokenizer_state state) const noexcept;
0042 inline next_result toFront() const noexcept { return next({}); }
0043 public:
0044 constexpr explicit QStringTokenizerBase(Haystack haystack, Needle needle, Qt::SplitBehavior sb, Qt::CaseSensitivity cs) noexcept
0045 : QStringTokenizerBaseBase{sb, cs}, m_haystack{haystack}, m_needle{needle} {}
0046
0047 class iterator;
0048 friend class iterator;
0049 class sentinel {
0050 friend constexpr bool operator==(sentinel, sentinel) noexcept { return true; }
0051 friend constexpr bool operator!=(sentinel, sentinel) noexcept { return false; }
0052 };
0053 class iterator {
0054 const QStringTokenizerBase *tokenizer;
0055 next_result current;
0056 friend class QStringTokenizerBase;
0057 explicit iterator(const QStringTokenizerBase &t) noexcept
0058 : tokenizer{&t}, current{t.toFront()} {}
0059 public:
0060 using difference_type = qsizetype;
0061 using value_type = Haystack;
0062 using pointer = const value_type*;
0063 using reference = const value_type&;
0064 using iterator_category = std::forward_iterator_tag;
0065
0066 iterator() noexcept = default;
0067
0068
0069 [[nodiscard]] constexpr const Haystack* operator->() const { return Q_ASSERT(current.ok), ¤t.value; }
0070 [[nodiscard]] constexpr const Haystack& operator*() const { return *operator->(); }
0071
0072 iterator& operator++() { advance(); return *this; }
0073 iterator operator++(int) { auto tmp = *this; advance(); return tmp; }
0074
0075 friend constexpr bool operator==(const iterator &lhs, sentinel) noexcept
0076 { return !lhs.current.ok; }
0077 friend constexpr bool operator!=(const iterator &lhs, sentinel) noexcept
0078 { return !operator==(lhs, sentinel{}); }
0079 friend constexpr bool operator==(sentinel, const iterator &rhs) noexcept
0080 { return !rhs.current.ok; }
0081 friend constexpr bool operator!=(sentinel, const iterator &rhs) noexcept
0082 { return !operator==(sentinel{}, rhs); }
0083 private:
0084 void advance() {
0085 Q_ASSERT(current.ok);
0086 current = tokenizer->next(current.state);
0087 }
0088 };
0089 using const_iterator = iterator;
0090
0091 using size_type = std::size_t;
0092 using difference_type = typename iterator::difference_type;
0093 using value_type = typename iterator::value_type;
0094 using pointer = typename iterator::pointer;
0095 using const_pointer = pointer;
0096 using reference = typename iterator::reference;
0097 using const_reference = reference;
0098
0099 [[nodiscard]] iterator begin() const noexcept { return iterator{*this}; }
0100 [[nodiscard]] iterator cbegin() const noexcept { return begin(); }
0101 [[nodiscard]] constexpr sentinel end() const noexcept { return {}; }
0102 [[nodiscard]] constexpr sentinel cend() const noexcept { return {}; }
0103
0104 private:
0105 Haystack m_haystack;
0106 Needle m_needle;
0107 };
0108
0109 QT_BEGIN_INCLUDE_NAMESPACE
0110 #include <QtCore/qstringview.h>
0111 QT_END_INCLUDE_NAMESPACE
0112
0113 namespace QtPrivate {
0114 namespace Tok {
0115
0116 constexpr qsizetype tokenSize(QChar) noexcept { return 1; }
0117 template <typename String>
0118 constexpr qsizetype tokenSize(const String &s) noexcept { return static_cast<qsizetype>(s.size()); }
0119
0120 template <typename String> struct ViewForImpl {};
0121 template <> struct ViewForImpl<QStringView> { using type = QStringView; };
0122 template <> struct ViewForImpl<QLatin1StringView> { using type = QLatin1StringView; };
0123 template <> struct ViewForImpl<QChar> { using type = QChar; };
0124 template <> struct ViewForImpl<QString> : ViewForImpl<QStringView> {};
0125 template <> struct ViewForImpl<QLatin1Char> : ViewForImpl<QChar> {};
0126 template <> struct ViewForImpl<char16_t> : ViewForImpl<QChar> {};
0127 template <> struct ViewForImpl<char16_t*> : ViewForImpl<QStringView> {};
0128 template <> struct ViewForImpl<const char16_t*> : ViewForImpl<QStringView> {};
0129 template <typename LHS, typename RHS>
0130 struct ViewForImpl<QStringBuilder<LHS, RHS>> : ViewForImpl<typename QStringBuilder<LHS,RHS>::ConvertTo> {};
0131 template <typename Char, typename...Args>
0132 struct ViewForImpl<std::basic_string<Char, Args...>> : ViewForImpl<Char*> {};
0133 #ifdef __cpp_lib_string_view
0134 template <typename Char, typename...Args>
0135 struct ViewForImpl<std::basic_string_view<Char, Args...>> : ViewForImpl<Char*> {};
0136 #endif
0137
0138
0139
0140
0141
0142 template <typename String>
0143 using ViewFor = typename ViewForImpl<typename std::decay<String>::type>::type;
0144
0145
0146
0147
0148
0149
0150
0151 template <typename String>
0152 struct PinForImpl { using type = ViewFor<String>; };
0153
0154
0155 template <>
0156 struct PinForImpl<QString> { using type = QString; };
0157
0158
0159 template <typename Char, typename...Args>
0160 struct PinForImpl<std::basic_string<Char, Args...>>
0161 { using type = std::basic_string<Char, Args...>; };
0162
0163
0164 template <typename LHS, typename RHS>
0165 struct PinForImpl<QStringBuilder<LHS, RHS>>
0166 : PinForImpl<typename QStringBuilder<LHS, RHS>::ConvertTo> {};
0167
0168 template <typename StringLike>
0169 using PinFor = typename PinForImpl<typename std::remove_cv<StringLike>::type>::type;
0170
0171 template <typename T> struct is_owning_string_type : std::false_type {};
0172 template <> struct is_owning_string_type<QString> : std::true_type {};
0173 template <typename...Args> struct is_owning_string_type<std::basic_string<Args...>> : std::true_type {};
0174
0175
0176 template <typename T, bool pinned = is_owning_string_type<T>::value>
0177 struct Pinning
0178 {
0179
0180 constexpr Pinning(const T&) noexcept {}
0181
0182
0183 constexpr T view(T t) const noexcept { return t; }
0184 };
0185
0186
0187 template <typename T>
0188 struct Pinning<T, true>
0189 {
0190 T m_string;
0191
0192
0193 constexpr Pinning(T &&s) noexcept : m_string{std::move(s)} {}
0194
0195 constexpr QStringView view(const T&) const noexcept { return m_string; }
0196 };
0197
0198
0199
0200
0201 template <typename T>
0202 struct NeedlePinning : Pinning<T>
0203 {
0204 using Pinning<T>::Pinning;
0205 template <typename Arg>
0206 constexpr auto needleView(Arg &&a) noexcept
0207 -> decltype(this->view(std::forward<Arg>(a)))
0208 { return this->view(std::forward<Arg>(a)); }
0209 };
0210
0211 template <typename T>
0212 struct HaystackPinning : Pinning<T>
0213 {
0214 using Pinning<T>::Pinning;
0215 template <typename Arg>
0216 constexpr auto haystackView(Arg &&a) noexcept
0217 -> decltype(this->view(std::forward<Arg>(a)))
0218 { return this->view(std::forward<Arg>(a)); }
0219 };
0220
0221
0222
0223
0224
0225
0226 template <typename Haystack, typename Needle>
0227 using TokenizerBase = QStringTokenizerBase<ViewFor<Haystack>, ViewFor<Needle>>;
0228 }
0229 }
0230
0231 template <typename Haystack, typename Needle>
0232 class QStringTokenizer
0233 : private QtPrivate::Tok::HaystackPinning<Haystack>,
0234 private QtPrivate::Tok::NeedlePinning<Needle>,
0235 public QtPrivate::Tok::TokenizerBase<Haystack, Needle>
0236 {
0237 using HPin = QtPrivate::Tok::HaystackPinning<Haystack>;
0238 using NPin = QtPrivate::Tok::NeedlePinning<Needle>;
0239 using Base = QtPrivate::Tok::TokenizerBase<Haystack, Needle>;
0240 template <typename Container, typename HPin>
0241 struct if_haystack_not_pinned_impl : std::enable_if<std::is_empty<HPin>::value, bool> {};
0242 template <typename Container>
0243 using if_haystack_not_pinned = typename if_haystack_not_pinned_impl<Container, HPin>::type;
0244 template <typename Container, typename Iterator = decltype(std::begin(std::declval<Container>()))>
0245 using if_compatible_container = typename std::enable_if<
0246 std::is_convertible<
0247 typename Base::value_type,
0248 typename std::iterator_traits<Iterator>::value_type
0249 >::value,
0250 bool
0251 >::type;
0252 public:
0253 using value_type = typename Base::value_type;
0254 using difference_type = typename Base::difference_type;
0255 using size_type = typename Base::size_type;
0256 using reference = typename Base::reference;
0257 using const_reference = typename Base::const_reference;
0258 using pointer = typename Base::pointer;
0259 using const_pointer = typename Base::const_pointer;
0260 using iterator = typename Base::iterator;
0261 using const_iterator = typename Base::const_iterator;
0262 using sentinel = typename Base::sentinel;
0263
0264 #ifdef Q_QDOC
0265 [[nodiscard]] iterator begin() const noexcept { return Base::begin(); }
0266 [[nodiscard]] iterator cbegin() const noexcept { return begin(); }
0267 [[nodiscard]] constexpr sentinel end() const noexcept { return {}; }
0268 [[nodiscard]] constexpr sentinel cend() const noexcept { return {}; }
0269 #endif
0270
0271 constexpr explicit QStringTokenizer(Haystack haystack, Needle needle,
0272 Qt::CaseSensitivity cs,
0273 Qt::SplitBehavior sb = Qt::KeepEmptyParts)
0274 noexcept(std::is_nothrow_copy_constructible<QStringTokenizer>::value)
0275
0276
0277
0278
0279 : HPin{std::forward<Haystack>(haystack)},
0280 NPin{std::forward<Needle>(needle)},
0281
0282
0283 Base{this->haystackView(haystack),
0284 this->needleView(needle), sb, cs}
0285 {}
0286 constexpr explicit QStringTokenizer(Haystack haystack, Needle needle,
0287 Qt::SplitBehavior sb = Qt::KeepEmptyParts,
0288 Qt::CaseSensitivity cs = Qt::CaseSensitive)
0289 noexcept(std::is_nothrow_copy_constructible<QStringTokenizer>::value)
0290 : HPin{std::forward<Haystack>(haystack)},
0291 NPin{std::forward<Needle>(needle)},
0292 Base{this->haystackView(haystack),
0293 this->needleView(needle), sb, cs}
0294 {}
0295
0296 #ifdef Q_QDOC
0297 template<typename LContainer> LContainer toContainer(LContainer &&c = {}) const & {}
0298 template<typename RContainer> RContainer toContainer(RContainer &&c = {}) const && {}
0299 #else
0300 template<typename Container = QList<value_type>, if_compatible_container<Container> = true>
0301 Container toContainer(Container &&c = {}) const &
0302 {
0303 for (auto e : *this)
0304 c.emplace_back(e);
0305 return std::forward<Container>(c);
0306 }
0307 template<typename Container = QList<value_type>, if_compatible_container<Container> = true,
0308 if_haystack_not_pinned<Container> = true>
0309 Container toContainer(Container &&c = {}) const &&
0310 {
0311 for (auto e : *this)
0312 c.emplace_back(e);
0313 return std::forward<Container>(c);
0314 }
0315 #endif
0316 };
0317
0318 namespace QtPrivate {
0319 namespace Tok {
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331 #define Q_TOK_RESULT \
0332 QStringTokenizer< \
0333 QtPrivate::Tok::PinFor<Haystack>, \
0334 QtPrivate::Tok::PinFor<Needle> \
0335 > \
0336
0337 template <typename Haystack, typename Needle>
0338 using TokenizerResult = Q_TOK_RESULT;
0339 template <typename Haystack, typename Needle>
0340 using is_nothrow_constructible_from = std::is_nothrow_copy_constructible<TokenizerResult<Haystack, Needle>>;
0341 }
0342 }
0343
0344 #ifdef __cpp_deduction_guides
0345
0346
0347 template <typename Haystack, typename Needle>
0348 QStringTokenizer(Haystack&&, Needle&&)
0349 -> Q_TOK_RESULT;
0350 template <typename Haystack, typename Needle>
0351 QStringTokenizer(Haystack&&, Needle&&, Qt::SplitBehavior)
0352 -> Q_TOK_RESULT;
0353 template <typename Haystack, typename Needle>
0354 QStringTokenizer(Haystack&&, Needle&&, Qt::SplitBehavior, Qt::CaseSensitivity)
0355 -> Q_TOK_RESULT;
0356 template <typename Haystack, typename Needle>
0357 QStringTokenizer(Haystack&&, Needle&&, Qt::CaseSensitivity)
0358 -> Q_TOK_RESULT;
0359 template <typename Haystack, typename Needle>
0360 QStringTokenizer(Haystack&&, Needle&&, Qt::CaseSensitivity, Qt::SplitBehavior)
0361 -> Q_TOK_RESULT;
0362 #endif
0363
0364 #undef Q_TOK_RESULT
0365
0366 template <typename Haystack, typename Needle, typename...Flags>
0367 [[nodiscard]] constexpr auto
0368 qTokenize(Haystack &&h, Needle &&n, Flags...flags)
0369 noexcept(QtPrivate::Tok::is_nothrow_constructible_from<Haystack, Needle>::value)
0370 -> decltype(QtPrivate::Tok::TokenizerResult<Haystack, Needle>{std::forward<Haystack>(h),
0371 std::forward<Needle>(n), flags...})
0372 { return QtPrivate::Tok::TokenizerResult<Haystack, Needle>{std::forward<Haystack>(h),
0373 std::forward<Needle>(n),
0374 flags...}; }
0375
0376 template <typename Haystack, typename Needle>
0377 auto QStringTokenizerBase<Haystack, Needle>::next(tokenizer_state state) const noexcept -> next_result
0378 {
0379 while (true) {
0380 if (state.end < 0) {
0381
0382 return {{}, false, state};
0383 }
0384 state.end = m_haystack.indexOf(m_needle, state.start + state.extra, m_cs);
0385 Haystack result;
0386 if (state.end >= 0) {
0387
0388 result = m_haystack.sliced(state.start, state.end - state.start);
0389 const auto ns = QtPrivate::Tok::tokenSize(m_needle);
0390 state.start = state.end + ns;
0391 state.extra = (ns == 0 ? 1 : 0);
0392 } else {
0393
0394 result = m_haystack.sliced(state.start);
0395 }
0396 if ((m_sb & Qt::SkipEmptyParts) && result.isEmpty())
0397 continue;
0398 return {result, true, state};
0399 }
0400 }
0401
0402 QT_END_NAMESPACE
0403
0404 #endif