Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/QtCore/qutf8stringview.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 #ifndef QUTF8STRINGVIEW_H
0004 #define QUTF8STRINGVIEW_H
0005 
0006 #if 0
0007 #pragma qt_class(QUtf8StringView)
0008 #endif
0009 
0010 #include <QtCore/qstringalgorithms.h>
0011 #include <QtCore/qstringfwd.h>
0012 #include <QtCore/qarraydata.h> // for QContainerImplHelper
0013 #include <QtCore/qbytearrayview.h>
0014 
0015 #include <string>
0016 #include <string_view>
0017 #include <QtCore/q20type_traits.h>
0018 
0019 QT_BEGIN_NAMESPACE
0020 
0021 namespace QtPrivate {
0022 template <typename Char>
0023 using IsCompatibleChar8TypeHelper = std::disjunction<
0024 #ifdef __cpp_char8_t
0025         std::is_same<Char, char8_t>,
0026 #endif
0027         std::is_same<Char, char>,
0028         std::is_same<Char, uchar>,
0029         std::is_same<Char, signed char>
0030     >;
0031 template <typename Char>
0032 using IsCompatibleChar8Type
0033     = IsCompatibleChar8TypeHelper<q20::remove_cvref_t<Char>>;
0034 
0035 template <typename Pointer>
0036 struct IsCompatiblePointer8Helper : std::false_type {};
0037 template <typename Char>
0038 struct IsCompatiblePointer8Helper<Char*>
0039     : IsCompatibleChar8Type<Char> {};
0040 template <typename Pointer>
0041 using IsCompatiblePointer8
0042     = IsCompatiblePointer8Helper<q20::remove_cvref_t<Pointer>>;
0043 
0044 template <typename T, typename Enable = void>
0045 struct IsContainerCompatibleWithQUtf8StringView : std::false_type {};
0046 
0047 template <typename T>
0048 struct IsContainerCompatibleWithQUtf8StringView<T, std::enable_if_t<std::conjunction_v<
0049         // lacking concepts and ranges, we accept any T whose std::data yields a suitable pointer ...
0050         IsCompatiblePointer8<decltype(std::data(std::declval<const T &>()))>,
0051         // ... and that has a suitable size ...
0052         std::is_convertible<
0053             decltype(std::size(std::declval<const T &>())),
0054             qsizetype
0055         >,
0056         // ... and it's a range as it defines an iterator-like API
0057         IsCompatibleChar8Type<typename std::iterator_traits<
0058             decltype(std::begin(std::declval<const T &>()))>::value_type
0059         >,
0060         std::is_convertible<
0061             decltype( std::begin(std::declval<const T &>()) != std::end(std::declval<const T &>()) ),
0062             bool
0063         >,
0064 
0065         // This needs to be treated specially due to the empty vs null distinction
0066         std::negation<std::is_same<std::decay_t<T>, QByteArray>>,
0067 
0068         // This has a compatible value_type, but explicitly a different encoding
0069         std::negation<std::is_same<std::decay_t<T>, QLatin1StringView>>,
0070 
0071         // Don't make an accidental copy constructor
0072         std::negation<std::disjunction<
0073             std::is_same<std::decay_t<T>, QBasicUtf8StringView<true>>,
0074             std::is_same<std::decay_t<T>, QBasicUtf8StringView<false>>
0075         >>
0076     >>> : std::true_type {};
0077 
0078 struct hide_char8_t {
0079 #ifdef __cpp_char8_t
0080     using type = char8_t;
0081 #endif
0082 };
0083 
0084 struct wrap_char { using type = char; };
0085 
0086 } // namespace QtPrivate
0087 
0088 #ifdef Q_QDOC
0089 #define QBasicUtf8StringView QUtf8StringView
0090 #else
0091 template <bool UseChar8T>
0092 #endif
0093 class QBasicUtf8StringView
0094 {
0095 public:
0096 #ifndef Q_QDOC
0097     using storage_type = typename std::conditional<UseChar8T,
0098             QtPrivate::hide_char8_t,
0099             QtPrivate::wrap_char
0100         >::type::type;
0101 #else
0102     using storage_type = typename QtPrivate::hide_char8_t;
0103 #endif
0104     typedef const storage_type value_type;
0105     typedef qptrdiff difference_type;
0106     typedef qsizetype size_type;
0107     typedef value_type &reference;
0108     typedef value_type &const_reference;
0109     typedef value_type *pointer;
0110     typedef value_type *const_pointer;
0111 
0112     typedef pointer iterator;
0113     typedef const_pointer const_iterator;
0114     typedef std::reverse_iterator<iterator> reverse_iterator;
0115     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
0116 
0117 private:
0118     template <typename Char>
0119     using if_compatible_char = std::enable_if_t<QtPrivate::IsCompatibleChar8Type<Char>::value, bool>;
0120 
0121     template <typename Pointer>
0122     using if_compatible_pointer = std::enable_if_t<QtPrivate::IsCompatiblePointer8<Pointer>::value, bool>;
0123 
0124     template <typename T>
0125     using if_compatible_qstring_like = std::enable_if_t<std::is_same_v<T, QByteArray>, bool>;
0126 
0127     template <typename T>
0128     using if_compatible_container = std::enable_if_t<QtPrivate::IsContainerCompatibleWithQUtf8StringView<T>::value, bool>;
0129 
0130     template <typename Container>
0131     static constexpr qsizetype lengthHelperContainer(const Container &c) noexcept
0132     {
0133         return qsizetype(std::size(c));
0134     }
0135 
0136     // Note: Do not replace with std::size(const Char (&)[N]), cause the result
0137     // will be of by one.
0138     template <typename Char, size_t N>
0139     static constexpr qsizetype lengthHelperContainer(const Char (&str)[N]) noexcept
0140     {
0141         const auto it = std::char_traits<Char>::find(str, N, Char(0));
0142         const auto end = it ? it : std::next(str, N);
0143         return qsizetype(std::distance(str, end));
0144     }
0145 
0146     template <typename Char>
0147     static const storage_type *castHelper(const Char *str) noexcept
0148     { return reinterpret_cast<const storage_type*>(str); }
0149     static constexpr const storage_type *castHelper(const storage_type *str) noexcept
0150     { return str; }
0151 
0152 public:
0153     constexpr QBasicUtf8StringView() noexcept
0154         : m_data(nullptr), m_size(0) {}
0155     constexpr QBasicUtf8StringView(std::nullptr_t) noexcept
0156         : QBasicUtf8StringView() {}
0157 
0158     template <typename Char, if_compatible_char<Char> = true>
0159     constexpr QBasicUtf8StringView(const Char *str, qsizetype len)
0160         : m_data(castHelper(str)),
0161           m_size((Q_ASSERT(len >= 0), Q_ASSERT(str || !len), len)) {}
0162 
0163     template <typename Char, if_compatible_char<Char> = true>
0164     constexpr QBasicUtf8StringView(const Char *f, const Char *l)
0165         : QBasicUtf8StringView(f, l - f) {}
0166 
0167 #ifdef Q_QDOC
0168     template <typename Char, size_t N>
0169     constexpr QBasicUtf8StringView(const Char (&array)[N]) noexcept;
0170 
0171     template <typename Char>
0172     constexpr QBasicUtf8StringView(const Char *str) noexcept;
0173 #else
0174     template <typename Pointer, if_compatible_pointer<Pointer> = true>
0175     constexpr QBasicUtf8StringView(const Pointer &str) noexcept
0176         : QBasicUtf8StringView(str,
0177             str ? std::char_traits<std::remove_cv_t<std::remove_pointer_t<Pointer>>>::length(str) : 0) {}
0178 #endif
0179 
0180 #ifdef Q_QDOC
0181     QBasicUtf8StringView(const QByteArray &str) noexcept;
0182     constexpr QBasicUtf8StringView(const storage_type *d, qsizetype n) noexcept {};
0183 #else
0184     template <typename String, if_compatible_qstring_like<String> = true>
0185     QBasicUtf8StringView(const String &str) noexcept
0186         : QBasicUtf8StringView(str.isNull() ? nullptr : str.data(), qsizetype(str.size())) {}
0187 #endif
0188 
0189     template <typename Container, if_compatible_container<Container> = true>
0190     constexpr QBasicUtf8StringView(const Container &c) noexcept
0191         : QBasicUtf8StringView(std::data(c), lengthHelperContainer(c)) {}
0192 
0193 #if defined(__cpp_char8_t) && !defined(Q_QDOC)
0194     constexpr QBasicUtf8StringView(QBasicUtf8StringView<!UseChar8T> other)
0195         : QBasicUtf8StringView(other.data(), other.size()) {}
0196 #endif
0197 
0198     template <typename Char, size_t Size, if_compatible_char<Char> = true>
0199     [[nodiscard]] constexpr static QBasicUtf8StringView fromArray(const Char (&string)[Size]) noexcept
0200     { return QBasicUtf8StringView(string, Size); }
0201 
0202     [[nodiscard]] inline QString toString() const; // defined in qstring.h
0203 
0204     [[nodiscard]] constexpr qsizetype size() const noexcept { return m_size; }
0205     [[nodiscard]] constexpr const_pointer data() const noexcept { return m_data; }
0206 #ifdef __cpp_char8_t
0207     [[nodiscard]] const char8_t *utf8() const noexcept { return reinterpret_cast<const char8_t*>(m_data); }
0208 #endif
0209 
0210     [[nodiscard]] constexpr storage_type operator[](qsizetype n) const
0211     { verify(n, 1); return m_data[n]; }
0212 
0213     //
0214     // QString API
0215     //
0216 
0217     [[nodiscard]] constexpr storage_type at(qsizetype n) const { return (*this)[n]; }
0218 
0219     [[nodiscard]]
0220     constexpr QBasicUtf8StringView mid(qsizetype pos, qsizetype n = -1) const
0221     {
0222         using namespace QtPrivate;
0223         auto result = QContainerImplHelper::mid(size(), &pos, &n);
0224         return result == QContainerImplHelper::Null ? QBasicUtf8StringView() : QBasicUtf8StringView(m_data + pos, n);
0225     }
0226     [[nodiscard]]
0227     constexpr QBasicUtf8StringView left(qsizetype n) const
0228     {
0229         if (size_t(n) >= size_t(size()))
0230             n = size();
0231         return QBasicUtf8StringView(m_data, n);
0232     }
0233     [[nodiscard]]
0234     constexpr QBasicUtf8StringView right(qsizetype n) const
0235     {
0236         if (size_t(n) >= size_t(size()))
0237             n = size();
0238         return QBasicUtf8StringView(m_data + m_size - n, n);
0239     }
0240 
0241     [[nodiscard]] constexpr QBasicUtf8StringView sliced(qsizetype pos) const
0242     { verify(pos, 0); return QBasicUtf8StringView{m_data + pos, m_size - pos}; }
0243     [[nodiscard]] constexpr QBasicUtf8StringView sliced(qsizetype pos, qsizetype n) const
0244     { verify(pos, n); return QBasicUtf8StringView(m_data + pos, n); }
0245     [[nodiscard]] constexpr QBasicUtf8StringView first(qsizetype n) const
0246     { verify(0, n); return sliced(0, n); }
0247     [[nodiscard]] constexpr QBasicUtf8StringView last(qsizetype n) const
0248     { verify(0, n); return sliced(m_size - n, n); }
0249     [[nodiscard]] constexpr QBasicUtf8StringView chopped(qsizetype n) const
0250     { verify(0, n); return sliced(0, m_size - n); }
0251 
0252     constexpr void truncate(qsizetype n)
0253     { verify(0, n); m_size = n; }
0254     constexpr void chop(qsizetype n)
0255     { verify(0, n); m_size -= n; }
0256 
0257     [[nodiscard]] inline bool isValidUtf8() const noexcept
0258     {
0259         return QByteArrayView(reinterpret_cast<const char *>(data()), size()).isValidUtf8();
0260     }
0261 
0262     //
0263     // STL compatibility API:
0264     //
0265     [[nodiscard]] const_iterator begin()   const noexcept { return data(); }
0266     [[nodiscard]] const_iterator end()     const noexcept { return data() + size(); }
0267     [[nodiscard]] const_iterator cbegin()  const noexcept { return begin(); }
0268     [[nodiscard]] const_iterator cend()    const noexcept { return end(); }
0269     [[nodiscard]] const_reverse_iterator rbegin()  const noexcept { return const_reverse_iterator(end()); }
0270     [[nodiscard]] const_reverse_iterator rend()    const noexcept { return const_reverse_iterator(begin()); }
0271     [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return rbegin(); }
0272     [[nodiscard]] const_reverse_iterator crend()   const noexcept { return rend(); }
0273 
0274     [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
0275     [[nodiscard]] constexpr storage_type front() const { return Q_ASSERT(!empty()), m_data[0]; }
0276     [[nodiscard]] constexpr storage_type back()  const { return Q_ASSERT(!empty()), m_data[m_size - 1]; }
0277 
0278     [[nodiscard]] Q_IMPLICIT operator std::basic_string_view<storage_type>() const noexcept
0279     { return std::basic_string_view<storage_type>(data(), size_t(size())); }
0280 
0281     //
0282     // Qt compatibility API:
0283     //
0284     [[nodiscard]] constexpr bool isNull() const noexcept { return !m_data; }
0285     [[nodiscard]] constexpr bool isEmpty() const noexcept { return empty(); }
0286     [[nodiscard]] constexpr qsizetype length() const noexcept
0287     { return size(); }
0288 
0289     [[nodiscard]] int compare(QBasicUtf8StringView other,
0290                               Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
0291     {
0292         return QtPrivate::compareStrings(*this, other, cs);
0293     }
0294 
0295     [[nodiscard]] int compare(QStringView other,
0296                               Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
0297     [[nodiscard]] int compare(QLatin1StringView other,
0298                               Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
0299 
0300 private:
0301     [[nodiscard]] static inline int compare(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
0302     {
0303         return QtPrivate::compareStrings(QBasicUtf8StringView<false>(lhs.data(), lhs.size()),
0304                                          QBasicUtf8StringView<false>(rhs.data(), rhs.size()));
0305     }
0306 
0307     [[nodiscard]] friend inline bool operator==(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
0308     {
0309         return lhs.size() == rhs.size()
0310                && QtPrivate::equalStrings(QBasicUtf8StringView<false>(lhs.data(), lhs.size()),
0311                                           QBasicUtf8StringView<false>(rhs.data(), rhs.size()));
0312     }
0313     [[nodiscard]] friend inline bool operator!=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
0314     { return !operator==(lhs, rhs); }
0315 
0316 #ifdef __cpp_impl_three_way_comparison
0317     [[nodiscard]] friend inline auto operator<=>(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
0318     { return QBasicUtf8StringView::compare(lhs, rhs) <=> 0; }
0319 #else
0320     [[nodiscard]] friend inline bool operator<=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
0321     { return QBasicUtf8StringView::compare(lhs, rhs) <= 0; }
0322     [[nodiscard]] friend inline bool operator>=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
0323     { return QBasicUtf8StringView::compare(lhs, rhs) >= 0; }
0324     [[nodiscard]] friend inline bool operator<(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
0325     { return QBasicUtf8StringView::compare(lhs, rhs) < 0; }
0326     [[nodiscard]] friend inline bool operator>(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
0327     { return QBasicUtf8StringView::compare(lhs, rhs) > 0; }
0328 #endif
0329 
0330     Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
0331                                           [[maybe_unused]] qsizetype n = 1) const
0332     {
0333         Q_ASSERT(pos >= 0);
0334         Q_ASSERT(pos <= size());
0335         Q_ASSERT(n >= 0);
0336         Q_ASSERT(n <= size() - pos);
0337     }
0338     const storage_type *m_data;
0339     qsizetype m_size;
0340 };
0341 
0342 #ifdef Q_QDOC
0343 #undef QBasicUtf8StringView
0344 #else
0345 template <bool UseChar8T>
0346 Q_DECLARE_TYPEINFO_BODY(QBasicUtf8StringView<UseChar8T>, Q_PRIMITIVE_TYPE);
0347 
0348 template <typename QStringLike, std::enable_if_t<std::is_same_v<QStringLike, QByteArray>, bool> = true>
0349 [[nodiscard]] inline q_no_char8_t::QUtf8StringView qToUtf8StringViewIgnoringNull(const QStringLike &s) noexcept
0350 { return q_no_char8_t::QUtf8StringView(s.data(), s.size()); }
0351 #endif // Q_QDOC
0352 
0353 QT_END_NAMESPACE
0354 
0355 #endif /* QUTF8STRINGVIEW_H */