Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/QtCore/qanystringview.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) 2022 The Qt Company Ltd.
0002 // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
0003 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0004 #ifndef QANYSTRINGVIEW_H
0005 #define QANYSTRINGVIEW_H
0006 
0007 #include <QtCore/qlatin1stringview.h>
0008 #include <QtCore/qstringview.h>
0009 #include <QtCore/qutf8stringview.h>
0010 
0011 #ifdef __cpp_impl_three_way_comparison
0012 #include <compare>
0013 #endif
0014 #include <QtCore/q20type_traits.h>
0015 #include <limits>
0016 
0017 class tst_QAnyStringView;
0018 
0019 QT_BEGIN_NAMESPACE
0020 
0021 namespace QtPrivate {
0022 
0023 template <typename Tag, typename Result>
0024 struct wrapped { using type = Result; };
0025 
0026 template <typename Tag, typename Result>
0027 using wrapped_t = typename wrapped<Tag, Result>::type;
0028 
0029 } // namespace QtPrivate
0030 
0031 class QAnyStringView
0032 {
0033 public:
0034     typedef qptrdiff difference_type;
0035     typedef qsizetype size_type;
0036 private:
0037     static constexpr size_t SizeMask = (std::numeric_limits<size_t>::max)() / 4;
0038 #if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED)
0039     static constexpr int SizeShift = 2;
0040     static constexpr size_t Latin1Flag = 1;
0041 #else
0042     static constexpr int SizeShift = 0;
0043     static constexpr size_t Latin1Flag = SizeMask + 1;
0044 #endif
0045     static constexpr size_t TwoByteCodePointFlag = Latin1Flag << 1;
0046     static constexpr size_t TypeMask = ~(SizeMask << SizeShift);
0047     static_assert(TypeMask == (Latin1Flag|TwoByteCodePointFlag));
0048 
0049     // Tag bits
0050     //  0  0   Utf8
0051     //  0  1   Latin1
0052     //  1  0   Utf16
0053     //  1  1   Unused
0054     //  ^  ^ latin1
0055     //  | sizeof code-point == 2
0056     enum Tag : size_t {
0057         Utf8     = 0,
0058         Latin1   = Latin1Flag,
0059         Utf16    = TwoByteCodePointFlag,
0060         Unused   = TypeMask,
0061     };
0062 
0063     template <typename Char>
0064     using is_compatible_char = std::disjunction<
0065         QtPrivate::IsCompatibleCharType<Char>,
0066         QtPrivate::IsCompatibleChar8Type<Char>
0067     >;
0068 
0069     template <typename Char>
0070     using if_compatible_char = std::enable_if_t<is_compatible_char<Char>::value, bool>;
0071 
0072     template <typename Pointer>
0073     using if_compatible_pointer = std::enable_if_t<std::disjunction_v<
0074         QtPrivate::IsCompatiblePointer<Pointer>,
0075         QtPrivate::IsCompatiblePointer8<Pointer>
0076     >, bool>;
0077 
0078 
0079     template <typename T>
0080     using if_compatible_container = std::enable_if_t<std::disjunction_v<
0081         QtPrivate::IsContainerCompatibleWithQStringView<T>,
0082         QtPrivate::IsContainerCompatibleWithQUtf8StringView<T>
0083     >, bool>;
0084 
0085     template <typename QStringOrQByteArray, typename T>
0086     using if_convertible_to = std::enable_if_t<std::conjunction_v<
0087         // need to exclude a bunch of stuff, because we take by universal reference:
0088         std::negation<std::disjunction<
0089             std::is_same<q20::remove_cvref_t<T>, QAnyStringView::Tag>,
0090             std::is_same<q20::remove_cvref_t<T>, QAnyStringView>, // don't make a copy/move ctor
0091             std::is_pointer<std::decay_t<T>>, // const char*, etc
0092             is_compatible_char<T>, // don't create a QString/QByteArray, we have a ctor
0093             std::is_same<q20::remove_cvref_t<T>, QByteArray>,
0094             std::is_same<q20::remove_cvref_t<T>, QString>
0095         >>,
0096         // this is what we're really after:
0097         std::is_convertible<T, QStringOrQByteArray>
0098     >, bool>;
0099 
0100     // confirm we don't make an accidental copy constructor:
0101     static_assert(QtPrivate::IsContainerCompatibleWithQStringView<QAnyStringView>::value == false);
0102     static_assert(QtPrivate::IsContainerCompatibleWithQUtf8StringView<QAnyStringView>::value == false);
0103 
0104     template<typename Char>
0105     static constexpr bool isAsciiOnlyCharsAtCompileTime(Char *str, qsizetype sz) noexcept
0106     {
0107         // do not perform check if not at compile time
0108         if (!q20::is_constant_evaluated())
0109             return false;
0110         if constexpr (sizeof(Char) != sizeof(char)) {
0111             Q_UNUSED(str);
0112             Q_UNUSED(sz);
0113             return false;
0114         } else {
0115             for (qsizetype i = 0; i < sz; ++i) {
0116                 if (uchar(str[i]) > 0x7f)
0117                     return false;
0118             }
0119             return true;
0120         }
0121     }
0122 
0123     template<typename Char>
0124     static constexpr std::size_t encodeType(const Char *str, qsizetype sz) noexcept
0125     {
0126         // Utf16 if 16 bit, Latin1 if ASCII, else Utf8
0127         Q_ASSERT(sz >= 0);
0128         Q_ASSERT(sz <= qsizetype(SizeMask));
0129         Q_ASSERT(str || !sz);
0130         return (std::size_t(sz) << SizeShift)
0131                 | uint(sizeof(Char) == sizeof(char16_t)) * Tag::Utf16
0132                 | uint(isAsciiOnlyCharsAtCompileTime(str, sz)) * Tag::Latin1;
0133     }
0134 
0135     template <typename Char>
0136     static constexpr qsizetype lengthHelperPointer(const Char *str) noexcept
0137     {
0138         if (q20::is_constant_evaluated())
0139             return qsizetype(std::char_traits<Char>::length(str));
0140         if constexpr (sizeof(Char) == sizeof(char16_t))
0141             return QtPrivate::qustrlen(reinterpret_cast<const char16_t*>(str));
0142         else
0143             return qsizetype(strlen(reinterpret_cast<const char*>(str)));
0144     }
0145 
0146     static QChar toQChar(char ch) noexcept { return toQChar(QLatin1Char{ch}); } // we don't handle UTF-8 multibytes
0147     static QChar toQChar(QChar ch) noexcept { return ch; }
0148     static QChar toQChar(QLatin1Char ch) noexcept { return ch; }
0149 
0150     struct QCharContainer { // private, so users can't pass their own
0151         explicit QCharContainer() = default;
0152         QChar ch;
0153     };
0154 
0155     explicit constexpr QAnyStringView(const void *d, qsizetype n, std::size_t sizeAndType) noexcept
0156         : m_data{d}, m_size{std::size_t(n) | (sizeAndType & TypeMask)} {}
0157 public:
0158     constexpr QAnyStringView() noexcept
0159         : m_data{nullptr}, m_size{0} {}
0160     constexpr QAnyStringView(std::nullptr_t) noexcept
0161         : QAnyStringView() {}
0162 
0163     template <typename Char, if_compatible_char<Char> = true>
0164     constexpr QAnyStringView(const Char *str, qsizetype len)
0165         : m_data{str}, m_size{encodeType<Char>(str, len)}
0166     {
0167     }
0168 
0169     template <typename Char, if_compatible_char<Char> = true>
0170     constexpr QAnyStringView(const Char *f, const Char *l)
0171         : QAnyStringView(f, l - f) {}
0172 
0173 #ifdef Q_QDOC
0174     template <typename Char, size_t N>
0175     constexpr QAnyStringView(const Char (&array)[N]) noexcept;
0176 
0177     template <typename Char>
0178     constexpr QAnyStringView(const Char *str) noexcept;
0179 #else
0180 
0181     template <typename Pointer, if_compatible_pointer<Pointer> = true>
0182     constexpr QAnyStringView(const Pointer &str) noexcept
0183         : QAnyStringView{str, str ? lengthHelperPointer(str) : 0} {}
0184 #endif
0185 
0186     // defined in qstring.h
0187     inline QAnyStringView(const QByteArray &str) noexcept; // TODO: Should we have this at all? Remove?
0188     inline QAnyStringView(const QString &str) noexcept;
0189     inline constexpr QAnyStringView(QLatin1StringView str) noexcept;
0190 
0191     template <typename Container, if_compatible_container<Container> = true>
0192     constexpr Q_ALWAYS_INLINE QAnyStringView(const Container &c) noexcept
0193         : QAnyStringView(std::data(c), QtPrivate::lengthHelperContainer(c)) {}
0194 
0195     template <typename Container, if_convertible_to<QString, Container> = true>
0196     constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t<Container, QString> &&capacity = {})
0197             //noexcept(std::is_nothrow_constructible_v<QString, Container>)
0198         : QAnyStringView(capacity = std::forward<Container>(c)) {}
0199 
0200     template <typename Container, if_convertible_to<QByteArray, Container> = true>
0201     constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t<Container, QByteArray> &&capacity = {})
0202             //noexcept(std::is_nothrow_constructible_v<QByteArray, Container>)
0203         : QAnyStringView(capacity = std::forward<Container>(c)) {}
0204     template <typename Char, if_compatible_char<Char> = true>
0205     constexpr QAnyStringView(const Char &c) noexcept
0206         : QAnyStringView{&c, 1} {}
0207     template <typename Char, if_convertible_to<QChar, Char> = true>
0208     constexpr QAnyStringView(Char ch, QCharContainer &&capacity = QCharContainer()) noexcept
0209         : QAnyStringView{&(capacity.ch = ch), 1} {}
0210 
0211     template <typename Char, typename Container = decltype(QChar::fromUcs4(U'x')),
0212               std::enable_if_t<std::is_same_v<Char, char32_t>, bool> = true>
0213     constexpr QAnyStringView(Char c, Container &&capacity = {}) noexcept
0214         : QAnyStringView(capacity = QChar::fromUcs4(c)) {}
0215 
0216     constexpr QAnyStringView(QStringView v) noexcept
0217         : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {}
0218 
0219     template <bool UseChar8T>
0220     constexpr QAnyStringView(QBasicUtf8StringView<UseChar8T> v) noexcept
0221         : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {}
0222 
0223     template <typename Char, size_t Size, if_compatible_char<Char> = true>
0224     [[nodiscard]] constexpr static QAnyStringView fromArray(const Char (&string)[Size]) noexcept
0225     { return QAnyStringView(string, Size); }
0226 
0227     // defined in qstring.h:
0228     template <typename Visitor>
0229     inline constexpr decltype(auto) visit(Visitor &&v) const;
0230 
0231     [[nodiscard]]
0232     constexpr QAnyStringView mid(qsizetype pos, qsizetype n = -1) const
0233     {
0234         using namespace QtPrivate;
0235         auto result = QContainerImplHelper::mid(size(), &pos, &n);
0236         return result == QContainerImplHelper::Null ? QAnyStringView() : sliced(pos, n);
0237     }
0238     [[nodiscard]]
0239     constexpr QAnyStringView left(qsizetype n) const
0240     {
0241         if (size_t(n) >= size_t(size()))
0242             n = size();
0243         return sliced(0, n);
0244     }
0245     [[nodiscard]]
0246     constexpr QAnyStringView right(qsizetype n) const
0247     {
0248         if (size_t(n) >= size_t(size()))
0249             n = size();
0250         return sliced(size() - n, n);
0251     }
0252 
0253     [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos) const
0254     { verify(pos, 0); auto r = *this; r.advanceData(pos); r.setSize(size() - pos); return r; }
0255     [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos, qsizetype n) const
0256     { verify(pos, n); auto r = *this; r.advanceData(pos); r.setSize(n); return r; }
0257     [[nodiscard]] constexpr QAnyStringView first(qsizetype n) const
0258     { verify(0, n); return sliced(0, n); }
0259     [[nodiscard]] constexpr QAnyStringView last(qsizetype n) const
0260     { verify(0, n); return sliced(size() - n, n); }
0261     [[nodiscard]] constexpr QAnyStringView chopped(qsizetype n) const
0262     { verify(0, n); return sliced(0, size() - n); }
0263 
0264     constexpr void truncate(qsizetype n)
0265     { verify(0, n); setSize(n); }
0266     constexpr void chop(qsizetype n)
0267     { verify(0, n); setSize(size() - n); }
0268 
0269 
0270     [[nodiscard]] inline QString toString() const; // defined in qstring.h
0271 
0272     [[nodiscard]] constexpr qsizetype size() const noexcept
0273     { return qsizetype((m_size >> SizeShift) & SizeMask); }
0274     [[nodiscard]] constexpr const void *data() const noexcept { return m_data; }
0275 
0276     [[nodiscard]] Q_CORE_EXPORT static int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
0277     [[nodiscard]] Q_CORE_EXPORT static bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept;
0278 
0279     static constexpr inline bool detects_US_ASCII_at_compile_time =
0280 #ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
0281             true
0282 #else
0283             false
0284 #endif
0285             ;
0286 
0287     //
0288     // STL compatibility API:
0289     //
0290     [[nodiscard]] constexpr QChar front() const; // NOT noexcept!
0291     [[nodiscard]] constexpr QChar back() const; // NOT noexcept!
0292     [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
0293     [[nodiscard]] constexpr qsizetype size_bytes() const noexcept
0294     { return size() * charSize(); }
0295 
0296     //
0297     // Qt compatibility API:
0298     //
0299     [[nodiscard]] constexpr bool isNull() const noexcept { return !m_data; }
0300     [[nodiscard]] constexpr bool isEmpty() const noexcept { return empty(); }
0301     [[nodiscard]] constexpr qsizetype length() const noexcept
0302     { return size(); }
0303 
0304 private:
0305     [[nodiscard]] friend inline bool operator==(QAnyStringView lhs, QAnyStringView rhs) noexcept
0306     { return QAnyStringView::equal(lhs, rhs); }
0307     [[nodiscard]] friend inline bool operator!=(QAnyStringView lhs, QAnyStringView rhs) noexcept
0308     { return !QAnyStringView::equal(lhs, rhs); }
0309 
0310 #if defined(__cpp_impl_three_way_comparison) && !defined(Q_QDOC)
0311     [[nodiscard]] friend inline auto operator<=>(QAnyStringView lhs, QAnyStringView rhs) noexcept
0312     { return QAnyStringView::compare(lhs, rhs) <=> 0; }
0313 #else
0314     [[nodiscard]] friend inline bool operator<=(QAnyStringView lhs, QAnyStringView rhs) noexcept
0315     { return QAnyStringView::compare(lhs, rhs) <= 0; }
0316     [[nodiscard]] friend inline bool operator>=(QAnyStringView lhs, QAnyStringView rhs) noexcept
0317     { return QAnyStringView::compare(lhs, rhs) >= 0; }
0318     [[nodiscard]] friend inline bool operator<(QAnyStringView lhs, QAnyStringView rhs) noexcept
0319     { return QAnyStringView::compare(lhs, rhs) < 0; }
0320     [[nodiscard]] friend inline bool operator>(QAnyStringView lhs, QAnyStringView rhs) noexcept
0321     { return QAnyStringView::compare(lhs, rhs) > 0; }
0322 #endif
0323 
0324 #ifndef QT_NO_DEBUG_STREAM
0325     Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s);
0326 #endif
0327 
0328     [[nodiscard]] constexpr Tag tag() const noexcept { return Tag{m_size & TypeMask}; }
0329     [[nodiscard]] constexpr bool isUtf16() const noexcept { return tag() == Tag::Utf16; }
0330     [[nodiscard]] constexpr bool isUtf8() const noexcept { return tag() == Tag::Utf8; }
0331     [[nodiscard]] constexpr bool isLatin1() const noexcept { return tag() == Tag::Latin1; }
0332     [[nodiscard]] constexpr QStringView asStringView() const
0333     { return Q_ASSERT(isUtf16()), QStringView{m_data_utf16, size()}; }
0334     [[nodiscard]] constexpr q_no_char8_t::QUtf8StringView asUtf8StringView() const
0335     { return Q_ASSERT(isUtf8()), q_no_char8_t::QUtf8StringView{m_data_utf8, size()}; }
0336     [[nodiscard]] inline constexpr QLatin1StringView asLatin1StringView() const;
0337     [[nodiscard]] constexpr size_t charSize() const noexcept { return isUtf16() ? 2 : 1; }
0338     constexpr void setSize(qsizetype sz) noexcept { m_size = size_t(sz) | tag(); }
0339     constexpr void advanceData(qsizetype delta) noexcept
0340     { m_data_utf8 += delta * charSize(); }
0341     Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
0342                                           [[maybe_unused]] qsizetype n = 1) const
0343     {
0344         Q_ASSERT(pos >= 0);
0345         Q_ASSERT(pos <= size());
0346         Q_ASSERT(n >= 0);
0347         Q_ASSERT(n <= size() - pos);
0348     }
0349     union {
0350         const void *m_data;
0351         const char *m_data_utf8;
0352         const char16_t *m_data_utf16;
0353     };
0354     size_t m_size;
0355     friend class ::tst_QAnyStringView;
0356 };
0357 Q_DECLARE_TYPEINFO(QAnyStringView, Q_PRIMITIVE_TYPE);
0358 
0359 template <typename QStringLike, std::enable_if_t<std::disjunction_v<
0360         std::is_same<QStringLike, QString>,
0361         std::is_same<QStringLike, QByteArray>
0362     >, bool> = true>
0363 [[nodiscard]] inline QAnyStringView qToAnyStringViewIgnoringNull(const QStringLike &s) noexcept
0364 { return QAnyStringView(s.data(), s.size()); }
0365 
0366 QT_END_NAMESPACE
0367 
0368 #endif /* QANYSTRINGVIEW_H */