Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/QtCore/qstringtokenizer.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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 // Qt-Security score:critical reason:data-parser
0004 
0005 #ifndef QSTRINGTOKENIZER_H
0006 #define QSTRINGTOKENIZER_H
0007 
0008 #include <QtCore/qnamespace.h>
0009 #include <QtCore/qcontainerfwd.h>
0010 #include <iterator>
0011 
0012 QT_BEGIN_NAMESPACE
0013 
0014 template <typename, typename> class QStringBuilder;
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     class sentinel {
0052         friend constexpr bool operator==(sentinel, sentinel) noexcept { return true; }
0053         friend constexpr bool operator!=(sentinel, sentinel) noexcept { return false; }
0054     };
0055     class iterator {
0056         const QStringTokenizerBase *tokenizer;
0057         next_result current;
0058         friend class QStringTokenizerBase;
0059         explicit iterator(const QStringTokenizerBase &t) noexcept
0060             : tokenizer{&t}, current{t.toFront()} {}
0061     public:
0062         using difference_type = qsizetype;
0063         using value_type = Haystack;
0064         using pointer = const value_type*;
0065         using reference = const value_type&;
0066         using iterator_category = std::forward_iterator_tag;
0067 
0068         iterator() noexcept = default;
0069 
0070         // violates std::forward_iterator (returns a reference into the iterator)
0071         [[nodiscard]] constexpr const Haystack* operator->() const { return Q_ASSERT(current.ok), &current.value; }
0072         [[nodiscard]] constexpr const Haystack& operator*() const { return *operator->(); }
0073 
0074         iterator& operator++() { advance(); return *this; }
0075         iterator  operator++(int) { auto tmp = *this; advance(); return tmp; }
0076 
0077         friend constexpr bool operator==(const iterator &lhs, sentinel) noexcept
0078         { return !lhs.current.ok; }
0079         friend constexpr bool operator!=(const iterator &lhs, sentinel) noexcept
0080         { return !operator==(lhs, sentinel{}); }
0081         friend constexpr bool operator==(sentinel, const iterator &rhs) noexcept
0082         { return !rhs.current.ok; }
0083         friend constexpr bool operator!=(sentinel, const iterator &rhs) noexcept
0084         { return !operator==(sentinel{}, rhs); }
0085     private:
0086         void advance() {
0087             Q_ASSERT(current.ok);
0088             current = tokenizer->next(current.state);
0089         }
0090     };
0091     using const_iterator = iterator;
0092 
0093     using size_type = std::size_t;
0094     using difference_type = typename iterator::difference_type;
0095     using value_type = typename iterator::value_type;
0096     using pointer = typename iterator::pointer;
0097     using const_pointer = pointer;
0098     using reference = typename iterator::reference;
0099     using const_reference = reference;
0100 
0101     [[nodiscard]] iterator begin() const noexcept { return iterator{*this}; }
0102     [[nodiscard]] iterator cbegin() const noexcept { return begin(); }
0103     [[nodiscard]] constexpr sentinel end() const noexcept { return {}; }
0104     [[nodiscard]] constexpr sentinel cend() const noexcept { return {}; }
0105 
0106 private:
0107     Haystack m_haystack;
0108     Needle m_needle;
0109 };
0110 
0111 QT_BEGIN_INCLUDE_NAMESPACE
0112 #include <QtCore/qstringview.h>
0113 QT_END_INCLUDE_NAMESPACE
0114 
0115 namespace QtPrivate {
0116 namespace Tok {
0117 
0118     constexpr qsizetype tokenSize(QChar) noexcept { return 1; }
0119     template <typename String>
0120     constexpr qsizetype tokenSize(const String &s) noexcept { return static_cast<qsizetype>(s.size()); }
0121 
0122     template <typename String> struct ViewForImpl {};
0123     template <> struct ViewForImpl<QStringView>   { using type = QStringView; };
0124     template <> struct ViewForImpl<QLatin1StringView> { using type = QLatin1StringView; };
0125     template <> struct ViewForImpl<QChar>         { using type = QChar; };
0126     template <> struct ViewForImpl<QString>     : ViewForImpl<QStringView> {};
0127     template <> struct ViewForImpl<QLatin1Char> : ViewForImpl<QChar> {};
0128     template <> struct ViewForImpl<char16_t>    : ViewForImpl<QChar> {};
0129     template <> struct ViewForImpl<char16_t*>   : ViewForImpl<QStringView> {};
0130     template <> struct ViewForImpl<const char16_t*> : ViewForImpl<QStringView> {};
0131     template <typename LHS, typename RHS>
0132     struct ViewForImpl<QStringBuilder<LHS, RHS>> : ViewForImpl<typename QStringBuilder<LHS,RHS>::ConvertTo> {};
0133     template <typename Char, typename...Args>
0134     struct ViewForImpl<std::basic_string<Char, Args...>> : ViewForImpl<Char*> {};
0135 #ifdef __cpp_lib_string_view
0136     template <typename Char, typename...Args>
0137     struct ViewForImpl<std::basic_string_view<Char, Args...>> : ViewForImpl<Char*> {};
0138 #endif
0139 
0140     // This metafunction maps a StringLike to a View (currently, QChar,
0141     // QStringView, QLatin1StringView). This is what QStringTokenizerBase
0142     // operates on. QStringTokenizer adds pinning to keep rvalues alive
0143     // for the duration of the algorithm.
0144     template <typename String>
0145     using ViewFor = typename ViewForImpl<typename std::decay<String>::type>::type;
0146 
0147     // Pinning:
0148     // rvalues of owning string types need to be moved into QStringTokenizer
0149     // to keep them alive for the lifetime of the tokenizer. For lvalues, we
0150     // assume the user takes care of that.
0151 
0152     // default: don't pin anything (characters are pinned implicitly)
0153     template <typename String>
0154     struct PinForImpl { using type = ViewFor<String>; };
0155 
0156     // rvalue QString -> QString
0157     template <>
0158     struct PinForImpl<QString> { using type = QString; };
0159 
0160     // rvalue std::basic_string -> basic_string
0161     template <typename Char, typename...Args>
0162     struct PinForImpl<std::basic_string<Char, Args...>>
0163     { using type = std::basic_string<Char, Args...>; };
0164 
0165     // rvalue QStringBuilder -> pin as the nested ConvertTo type
0166     template <typename LHS, typename RHS>
0167     struct PinForImpl<QStringBuilder<LHS, RHS>>
0168         : PinForImpl<typename QStringBuilder<LHS, RHS>::ConvertTo> {};
0169 
0170     template <typename StringLike>
0171     using PinFor = typename PinForImpl<typename std::remove_cv<StringLike>::type>::type;
0172 
0173     template <typename T> struct is_owning_string_type : std::false_type {};
0174     template <> struct is_owning_string_type<QString> : std::true_type {};
0175     template <typename...Args> struct is_owning_string_type<std::basic_string<Args...>> : std::true_type {};
0176 
0177     // unpinned
0178     template <typename T, bool pinned = is_owning_string_type<T>::value>
0179     struct Pinning
0180     {
0181         // this is the storage for non-pinned types - no storage
0182         constexpr Pinning(const T&) noexcept {}
0183         // Since we don't store something, the view() method needs to be
0184         // given something it can return.
0185         constexpr T view(T t) const noexcept { return t; }
0186     };
0187 
0188     // pinned
0189     template <typename T>
0190     struct Pinning<T, true>
0191     {
0192         T m_string;
0193         // specialisation for owning string types (QString, std::u16string):
0194         // stores the string:
0195         constexpr Pinning(T &&s) noexcept : m_string{std::move(s)} {}
0196         // ... and thus view() uses that instead of the argument passed in:
0197         constexpr QStringView view(const T&) const noexcept { return m_string; }
0198     };
0199 
0200     // NeedlePinning and HaystackPinning are there to distinguish them as
0201     // base classes of QStringTokenizer. We use inheritance to reap the
0202     // empty base class optimization.
0203     template <typename T>
0204     struct NeedlePinning : Pinning<T>
0205     {
0206         using Pinning<T>::Pinning;
0207         template <typename Arg>
0208         constexpr auto needleView(Arg &&a) noexcept
0209             -> decltype(this->view(std::forward<Arg>(a)))
0210         { return this->view(std::forward<Arg>(a)); }
0211     };
0212 
0213     template <typename T>
0214     struct HaystackPinning : Pinning<T>
0215     {
0216         using Pinning<T>::Pinning;
0217         template <typename Arg>
0218         constexpr auto haystackView(Arg &&a) noexcept
0219             -> decltype(this->view(std::forward<Arg>(a)))
0220         { return this->view(std::forward<Arg>(a)); }
0221     };
0222 
0223     // The Base of a QStringTokenizer is QStringTokenizerBase for the views
0224     // corresponding to the Haystack and Needle template arguments
0225     //
0226     // ie. QStringTokenizer<QString, QString>
0227     //       : QStringTokenizerBase<QStringView, QStringView> (+ pinning)
0228     template <typename Haystack, typename Needle>
0229     using TokenizerBase = QStringTokenizerBase<ViewFor<Haystack>, ViewFor<Needle>>;
0230 } // namespace Tok
0231 } // namespace QtPrivate
0232 
0233 template <typename Haystack, typename Needle>
0234 class QStringTokenizer
0235     : private QtPrivate::Tok::HaystackPinning<Haystack>,
0236       private QtPrivate::Tok::NeedlePinning<Needle>,
0237       public  QtPrivate::Tok::TokenizerBase<Haystack, Needle>
0238 {
0239     using HPin = QtPrivate::Tok::HaystackPinning<Haystack>;
0240     using NPin = QtPrivate::Tok::NeedlePinning<Needle>;
0241     using Base = QtPrivate::Tok::TokenizerBase<Haystack, Needle>;
0242     template <typename Container, typename HPin>
0243     struct if_haystack_not_pinned_impl : std::enable_if<std::is_empty<HPin>::value, bool> {};
0244     template <typename Container>
0245     using if_haystack_not_pinned = typename if_haystack_not_pinned_impl<Container, HPin>::type;
0246     template <typename Container, typename Iterator = decltype(std::begin(std::declval<Container>()))>
0247     using if_compatible_container = typename std::enable_if<
0248             std::is_convertible<
0249                 typename Base::value_type,
0250                 typename std::iterator_traits<Iterator>::value_type
0251             >::value,
0252             bool
0253         >::type;
0254 public:
0255     using value_type      = typename Base::value_type;
0256     using difference_type = typename Base::difference_type;
0257     using size_type       = typename Base::size_type;
0258     using reference       = typename Base::reference;
0259     using const_reference = typename Base::const_reference;
0260     using pointer         = typename Base::pointer;
0261     using const_pointer   = typename Base::const_pointer;
0262     using iterator        = typename Base::iterator;
0263     using const_iterator  = typename Base::const_iterator;
0264     using sentinel        = typename Base::sentinel;
0265 
0266 #ifdef Q_QDOC
0267     [[nodiscard]] iterator begin() const noexcept { return Base::begin(); }
0268     [[nodiscard]] iterator cbegin() const noexcept { return begin(); }
0269     [[nodiscard]] constexpr sentinel end() const noexcept { return {}; }
0270     [[nodiscard]] constexpr sentinel cend() const noexcept { return {}; }
0271 #endif
0272 
0273     constexpr explicit QStringTokenizer(Haystack haystack, Needle needle,
0274                                         Qt::CaseSensitivity cs,
0275                                         Qt::SplitBehavior sb = Qt::KeepEmptyParts)
0276             noexcept(std::is_nothrow_copy_constructible<QStringTokenizer>::value)
0277           // here, we present the haystack to Pinning<>, for optional storing.
0278           // If it did store, haystack is moved-from and mustn't be touched
0279           // any longer, which is why view() for these Pinning<>s ignores the
0280           // argument.
0281         : HPin{std::forward<Haystack>(haystack)},
0282           NPin{std::forward<Needle>(needle)},
0283           // If Pinning<> didn't store, we pass the haystack (ditto needle)
0284           // to view() again, so it can be copied from there.
0285           Base{this->haystackView(haystack),
0286                this->needleView(needle), sb, cs}
0287     {}
0288     constexpr explicit QStringTokenizer(Haystack haystack, Needle needle,
0289                                         Qt::SplitBehavior sb = Qt::KeepEmptyParts,
0290                                         Qt::CaseSensitivity cs = Qt::CaseSensitive)
0291             noexcept(std::is_nothrow_copy_constructible<QStringTokenizer>::value)
0292         : HPin{std::forward<Haystack>(haystack)},
0293           NPin{std::forward<Needle>(needle)},
0294           Base{this->haystackView(haystack),
0295                this->needleView(needle), sb, cs}
0296     {}
0297 
0298 #ifdef Q_QDOC
0299     template<typename LContainer> LContainer toContainer(LContainer &&c = {}) const & {}
0300     template<typename RContainer> RContainer toContainer(RContainer &&c = {}) const && {}
0301 #else
0302     template<typename Container = QList<value_type>, if_compatible_container<Container> = true>
0303     Container toContainer(Container &&c = {}) const &
0304     {
0305         for (auto e : *this)
0306             c.emplace_back(e);
0307         return std::forward<Container>(c);
0308     }
0309     template<typename Container = QList<value_type>, if_compatible_container<Container> = true,
0310              if_haystack_not_pinned<Container> = true>
0311     Container toContainer(Container &&c = {}) const &&
0312     {
0313         for (auto e : *this)
0314             c.emplace_back(e);
0315         return std::forward<Container>(c);
0316     }
0317 #endif
0318 };
0319 
0320 namespace QtPrivate {
0321 namespace Tok {
0322 // This meta function just calculated the template arguments for the
0323 // QStringTokenizer (not -Base), based on the actual arguments passed
0324 // to qTokenize() (or the ctor, with CTAD). It basically detects rvalue
0325 // QString and std::basic_string and otherwise decays the arguments to
0326 // the respective view type.
0327 //
0328 // #define works around a C++ restriction: [temp.deduct.guide]/3 seems
0329 // to ask for the simple-template-id following the `->` of a deduction
0330 // guide to be identical to the class name for which we guide deduction.
0331 // In particular, Clang rejects a template alias there, while GCC accepts
0332 // it.
0333 #define Q_TOK_RESULT \
0334     QStringTokenizer< \
0335         QtPrivate::Tok::PinFor<Haystack>, \
0336         QtPrivate::Tok::PinFor<Needle> \
0337     > \
0338     /*end*/
0339 template <typename Haystack, typename Needle>
0340 using TokenizerResult = Q_TOK_RESULT;
0341 template <typename Haystack, typename Needle>
0342 using is_nothrow_constructible_from = std::is_nothrow_copy_constructible<TokenizerResult<Haystack, Needle>>;
0343 }
0344 }
0345 
0346 #ifdef __cpp_deduction_guides
0347 // these tell the compiler how to determine the QStringTokenizer
0348 // template arguments based on the constructor arguments (CTAD):
0349 template <typename Haystack, typename Needle>
0350 QStringTokenizer(Haystack&&, Needle&&)
0351     -> Q_TOK_RESULT;
0352 template <typename Haystack, typename Needle>
0353 QStringTokenizer(Haystack&&, Needle&&, Qt::SplitBehavior)
0354     -> Q_TOK_RESULT;
0355 template <typename Haystack, typename Needle>
0356 QStringTokenizer(Haystack&&, Needle&&, Qt::SplitBehavior, Qt::CaseSensitivity)
0357     -> Q_TOK_RESULT;
0358 template <typename Haystack, typename Needle>
0359 QStringTokenizer(Haystack&&, Needle&&, Qt::CaseSensitivity)
0360     -> Q_TOK_RESULT;
0361 template <typename Haystack, typename Needle>
0362 QStringTokenizer(Haystack&&, Needle&&, Qt::CaseSensitivity, Qt::SplitBehavior)
0363     -> Q_TOK_RESULT;
0364 #endif
0365 
0366 #undef Q_TOK_RESULT
0367 
0368 template <typename Haystack, typename Needle, typename...Flags>
0369 [[nodiscard]] constexpr auto
0370 qTokenize(Haystack &&h, Needle &&n, Flags...flags)
0371     noexcept(QtPrivate::Tok::is_nothrow_constructible_from<Haystack, Needle>::value)
0372     -> decltype(QtPrivate::Tok::TokenizerResult<Haystack, Needle>{std::forward<Haystack>(h),
0373                                                                   std::forward<Needle>(n), flags...})
0374 { return QtPrivate::Tok::TokenizerResult<Haystack, Needle>{std::forward<Haystack>(h),
0375                                                            std::forward<Needle>(n),
0376                                                            flags...}; }
0377 
0378 template <typename Haystack, typename Needle>
0379 auto QStringTokenizerBase<Haystack, Needle>::next(tokenizer_state state) const noexcept -> next_result
0380 {
0381     while (true) {
0382         if (state.end < 0) {
0383             // already at end:
0384             return {{}, false, state};
0385         }
0386         state.end = m_haystack.indexOf(m_needle, state.start + state.extra, m_cs);
0387         Haystack result;
0388         if (state.end >= 0) {
0389             // token separator found => return intermediate element:
0390             result = m_haystack.sliced(state.start, state.end - state.start);
0391             const auto ns = QtPrivate::Tok::tokenSize(m_needle);
0392             state.start = state.end + ns;
0393             state.extra = (ns == 0 ? 1 : 0);
0394         } else {
0395             // token separator not found => return final element:
0396             result = m_haystack.sliced(state.start);
0397         }
0398         if ((m_sb & Qt::SkipEmptyParts) && result.isEmpty())
0399             continue;
0400         return {result, true, state};
0401     }
0402 }
0403 
0404 QT_END_NAMESPACE
0405 
0406 #endif /* QSTRINGTOKENIZER_H */