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