Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:07:39

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 #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         // violates std::forward_iterator (returns a reference into the iterator)
0075         [[nodiscard]] constexpr const Haystack* operator->() const { return Q_ASSERT(current.ok), &current.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> // ODR protection
0114     [[nodiscard]] constexpr sentinel end() const noexcept { return {}; }
0115     template <bool = std::is_same<iterator, sentinel>::value> // ODR protection
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     // This metafunction maps a StringLike to a View (currently, QChar,
0153     // QStringView, QLatin1StringView). This is what QStringTokenizerBase
0154     // operates on. QStringTokenizer adds pinning to keep rvalues alive
0155     // for the duration of the algorithm.
0156     template <typename String>
0157     using ViewFor = typename ViewForImpl<typename std::decay<String>::type>::type;
0158 
0159     // Pinning:
0160     // rvalues of owning string types need to be moved into QStringTokenizer
0161     // to keep them alive for the lifetime of the tokenizer. For lvalues, we
0162     // assume the user takes care of that.
0163 
0164     // default: don't pin anything (characters are pinned implicitly)
0165     template <typename String>
0166     struct PinForImpl { using type = ViewFor<String>; };
0167 
0168     // rvalue QString -> QString
0169     template <>
0170     struct PinForImpl<QString> { using type = QString; };
0171 
0172     // rvalue std::basic_string -> basic_string
0173     template <typename Char, typename...Args>
0174     struct PinForImpl<std::basic_string<Char, Args...>>
0175     { using type = std::basic_string<Char, Args...>; };
0176 
0177     // rvalue QStringBuilder -> pin as the nested ConvertTo type
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     // unpinned
0190     template <typename T, bool pinned = is_owning_string_type<T>::value>
0191     struct Pinning
0192     {
0193         // this is the storage for non-pinned types - no storage
0194         constexpr Pinning(const T&) noexcept {}
0195         // Since we don't store something, the view() method needs to be
0196         // given something it can return.
0197         constexpr T view(T t) const noexcept { return t; }
0198     };
0199 
0200     // pinned
0201     template <typename T>
0202     struct Pinning<T, true>
0203     {
0204         T m_string;
0205         // specialisation for owning string types (QString, std::u16string):
0206         // stores the string:
0207         constexpr Pinning(T &&s) noexcept : m_string{std::move(s)} {}
0208         // ... and thus view() uses that instead of the argument passed in:
0209         constexpr QStringView view(const T&) const noexcept { return m_string; }
0210     };
0211 
0212     // NeedlePinning and HaystackPinning are there to distinguish them as
0213     // base classes of QStringTokenizer. We use inheritance to reap the
0214     // empty base class optimization.
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     // The Base of a QStringTokenizer is QStringTokenizerBase for the views
0236     // corresponding to the Haystack and Needle template arguments
0237     //
0238     // ie. QStringTokenizer<QString, QString>
0239     //       : QStringTokenizerBase<QStringView, QStringView> (+ pinning)
0240     template <typename Haystack, typename Needle>
0241     using TokenizerBase = QStringTokenizerBase<ViewFor<Haystack>, ViewFor<Needle>>;
0242 } // namespace Tok
0243 } // namespace QtPrivate
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           // here, we present the haystack to Pinning<>, for optional storing.
0290           // If it did store, haystack is moved-from and mustn't be touched
0291           // any longer, which is why view() for these Pinning<>s ignores the
0292           // argument.
0293         : HPin{std::forward<Haystack>(haystack)},
0294           NPin{std::forward<Needle>(needle)},
0295           // If Pinning<> didn't store, we pass the haystack (ditto needle)
0296           // to view() again, so it can be copied from there.
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 // This meta function just calculated the template arguments for the
0335 // QStringTokenizer (not -Base), based on the actual arguments passed
0336 // to qTokenize() (or the ctor, with CTAD). It basically detects rvalue
0337 // QString and std::basic_string and otherwise decays the arguments to
0338 // the respective view type.
0339 //
0340 // #define works around a C++ restriction: [temp.deduct.guide]/3 seems
0341 // to ask for the simple-template-id following the `->` of a deduction
0342 // guide to be identical to the class name for which we guide deduction.
0343 // In particular, Clang rejects a template alias there, while GCC accepts
0344 // it.
0345 #define Q_TOK_RESULT \
0346     QStringTokenizer< \
0347         QtPrivate::Tok::PinFor<Haystack>, \
0348         QtPrivate::Tok::PinFor<Needle> \
0349     > \
0350     /*end*/
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 // these tell the compiler how to determine the QStringTokenizer
0360 // template arguments based on the constructor arguments (CTAD):
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             // already at end:
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             // token separator found => return intermediate element:
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             // token separator not found => return final element:
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 /* QSTRINGTOKENIZER_H */