Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 09:09:34

0001 // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
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         // violates std::forward_iterator (returns a reference into the iterator)
0069         [[nodiscard]] constexpr const Haystack* operator->() const { return Q_ASSERT(current.ok), &current.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     // This metafunction maps a StringLike to a View (currently, QChar,
0139     // QStringView, QLatin1StringView). This is what QStringTokenizerBase
0140     // operates on. QStringTokenizer adds pinning to keep rvalues alive
0141     // for the duration of the algorithm.
0142     template <typename String>
0143     using ViewFor = typename ViewForImpl<typename std::decay<String>::type>::type;
0144 
0145     // Pinning:
0146     // rvalues of owning string types need to be moved into QStringTokenizer
0147     // to keep them alive for the lifetime of the tokenizer. For lvalues, we
0148     // assume the user takes care of that.
0149 
0150     // default: don't pin anything (characters are pinned implicitly)
0151     template <typename String>
0152     struct PinForImpl { using type = ViewFor<String>; };
0153 
0154     // rvalue QString -> QString
0155     template <>
0156     struct PinForImpl<QString> { using type = QString; };
0157 
0158     // rvalue std::basic_string -> basic_string
0159     template <typename Char, typename...Args>
0160     struct PinForImpl<std::basic_string<Char, Args...>>
0161     { using type = std::basic_string<Char, Args...>; };
0162 
0163     // rvalue QStringBuilder -> pin as the nested ConvertTo type
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     // unpinned
0176     template <typename T, bool pinned = is_owning_string_type<T>::value>
0177     struct Pinning
0178     {
0179         // this is the storage for non-pinned types - no storage
0180         constexpr Pinning(const T&) noexcept {}
0181         // Since we don't store something, the view() method needs to be
0182         // given something it can return.
0183         constexpr T view(T t) const noexcept { return t; }
0184     };
0185 
0186     // pinned
0187     template <typename T>
0188     struct Pinning<T, true>
0189     {
0190         T m_string;
0191         // specialisation for owning string types (QString, std::u16string):
0192         // stores the string:
0193         constexpr Pinning(T &&s) noexcept : m_string{std::move(s)} {}
0194         // ... and thus view() uses that instead of the argument passed in:
0195         constexpr QStringView view(const T&) const noexcept { return m_string; }
0196     };
0197 
0198     // NeedlePinning and HaystackPinning are there to distinguish them as
0199     // base classes of QStringTokenizer. We use inheritance to reap the
0200     // empty base class optimization.
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     // The Base of a QStringTokenizer is QStringTokenizerBase for the views
0222     // corresponding to the Haystack and Needle template arguments
0223     //
0224     // ie. QStringTokenizer<QString, QString>
0225     //       : QStringTokenizerBase<QStringView, QStringView> (+ pinning)
0226     template <typename Haystack, typename Needle>
0227     using TokenizerBase = QStringTokenizerBase<ViewFor<Haystack>, ViewFor<Needle>>;
0228 } // namespace Tok
0229 } // namespace QtPrivate
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           // here, we present the haystack to Pinning<>, for optional storing.
0276           // If it did store, haystack is moved-from and mustn't be touched
0277           // any longer, which is why view() for these Pinning<>s ignores the
0278           // argument.
0279         : HPin{std::forward<Haystack>(haystack)},
0280           NPin{std::forward<Needle>(needle)},
0281           // If Pinning<> didn't store, we pass the haystack (ditto needle)
0282           // to view() again, so it can be copied from there.
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 // This meta function just calculated the template arguments for the
0321 // QStringTokenizer (not -Base), based on the actual arguments passed
0322 // to qTokenize() (or the ctor, with CTAD). It basically detects rvalue
0323 // QString and std::basic_string and otherwise decays the arguments to
0324 // the respective view type.
0325 //
0326 // #define works around a C++ restriction: [temp.deduct.guide]/3 seems
0327 // to ask for the simple-template-id following the `->` of a deduction
0328 // guide to be identical to the class name for which we guide deduction.
0329 // In particular, Clang rejects a template alias there, while GCC accepts
0330 // it.
0331 #define Q_TOK_RESULT \
0332     QStringTokenizer< \
0333         QtPrivate::Tok::PinFor<Haystack>, \
0334         QtPrivate::Tok::PinFor<Needle> \
0335     > \
0336     /*end*/
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 // these tell the compiler how to determine the QStringTokenizer
0346 // template arguments based on the constructor arguments (CTAD):
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             // already at end:
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             // token separator found => return intermediate element:
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             // token separator not found => return final element:
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 /* QSTRINGTOKENIZER_H */