Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qanystringview.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4#ifndef QANYSTRINGVIEW_H
5#define QANYSTRINGVIEW_H
6
7#include <QtCore/qcompare.h>
8#include <QtCore/qlatin1stringview.h>
9#include <QtCore/qstringview.h>
10#include <QtCore/qutf8stringview.h>
11
12#ifdef __cpp_impl_three_way_comparison
13#include <compare>
14#endif
15#include <QtCore/q20type_traits.h>
16#include <limits>
17
18class tst_QAnyStringView;
19
21
22namespace QtPrivate {
23
24template <typename Tag, typename Result>
25struct wrapped { using type = Result; };
26
27template <typename Tag, typename Result>
29
30} // namespace QtPrivate
31
33{
34public:
37private:
38 static constexpr size_t SizeMask = (std::numeric_limits<size_t>::max)() / 4;
39#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED)
40 static constexpr int SizeShift = 2;
41 static constexpr size_t Latin1Flag = 1;
42#else
43 static constexpr int SizeShift = 0;
44 static constexpr size_t Latin1Flag = SizeMask + 1;
45#endif
46 static constexpr size_t TwoByteCodePointFlag = Latin1Flag << 1;
47 static constexpr size_t TypeMask = ~(SizeMask << SizeShift);
48 static_assert(TypeMask == (Latin1Flag|TwoByteCodePointFlag));
49
50 // Tag bits
51 // 0 0 Utf8
52 // 0 1 Latin1
53 // 1 0 Utf16
54 // 1 1 Unused
55 // ^ ^ latin1
56 // | sizeof code-point == 2
57 enum Tag : size_t {
58 Utf8 = 0,
59 Latin1 = Latin1Flag,
60 Utf16 = TwoByteCodePointFlag,
61 Unused = TypeMask,
62 };
63
64 template <typename Char>
65 using is_compatible_char = std::disjunction<
68 >;
69
70 template <typename Char>
71 using if_compatible_char = std::enable_if_t<is_compatible_char<Char>::value, bool>;
72
73 template <typename Pointer>
74 using if_compatible_pointer = std::enable_if_t<std::disjunction_v<
77 >, bool>;
78
79
80 template <typename T>
81 using if_compatible_container = std::enable_if_t<std::disjunction_v<
84 >, bool>;
85
86 template <typename QStringOrQByteArray, typename T>
87 using if_convertible_to = std::enable_if_t<std::conjunction_v<
88 // need to exclude a bunch of stuff, because we take by universal reference:
89 std::negation<std::disjunction<
90 std::is_same<q20::remove_cvref_t<T>, QAnyStringView::Tag>,
91 std::is_same<q20::remove_cvref_t<T>, QAnyStringView>, // don't make a copy/move ctor
92 std::is_pointer<std::decay_t<T>>, // const char*, etc
93 is_compatible_char<T>, // don't create a QString/QByteArray, we have a ctor
94 std::is_same<q20::remove_cvref_t<T>, QByteArray>,
95 std::is_same<q20::remove_cvref_t<T>, QString>
96 >>,
97 // this is what we're really after:
98 std::is_convertible<T, QStringOrQByteArray>
99 >, bool>;
100
101 // confirm we don't make an accidental copy constructor:
104
105 template<typename Char>
106 static constexpr bool isAsciiOnlyCharsAtCompileTime(Char *str, qsizetype sz) noexcept
107 {
108 // do not perform check if not at compile time
110 return false;
111 if constexpr (sizeof(Char) != sizeof(char)) {
112 Q_UNUSED(str);
113 Q_UNUSED(sz);
114 return false;
115 } else {
116 for (qsizetype i = 0; i < sz; ++i) {
117 if (uchar(str[i]) > 0x7f)
118 return false;
119 }
120 return true;
121 }
122 }
123
124 template<typename Char>
125 static constexpr std::size_t encodeType(const Char *str, qsizetype sz) noexcept
126 {
127 // Utf16 if 16 bit, Latin1 if ASCII, else Utf8
128 Q_ASSERT(sz >= 0);
129 Q_ASSERT(sz <= qsizetype(SizeMask));
130 Q_ASSERT(str || !sz);
131 return (std::size_t(sz) << SizeShift)
132 | uint(sizeof(Char) == sizeof(char16_t)) * Tag::Utf16
133 | uint(isAsciiOnlyCharsAtCompileTime(str, sz)) * Tag::Latin1;
134 }
135
136 template <typename Char>
137 static constexpr qsizetype lengthHelperPointer(const Char *str) noexcept
138 {
141 if constexpr (sizeof(Char) == sizeof(char16_t))
142 return QtPrivate::qustrlen(reinterpret_cast<const char16_t*>(str));
143 else
144 return qsizetype(strlen(reinterpret_cast<const char*>(str)));
145 }
146
147 static QChar toQChar(char ch) noexcept { return toQChar(QLatin1Char{ch}); } // we don't handle UTF-8 multibytes
148 static QChar toQChar(QChar ch) noexcept { return ch; }
149 static QChar toQChar(QLatin1Char ch) noexcept { return ch; }
150
151 struct QCharContainer { // private, so users can't pass their own
152 explicit QCharContainer() = default;
153 QChar ch;
154 };
155
156 explicit constexpr QAnyStringView(const void *d, qsizetype n, std::size_t sizeAndType) noexcept
157 : m_data{d}, m_size{std::size_t(n) | (sizeAndType & TypeMask)} {}
158public:
159 constexpr QAnyStringView() noexcept
160 : m_data{nullptr}, m_size{0} {}
161 constexpr QAnyStringView(std::nullptr_t) noexcept
162 : QAnyStringView() {}
163
164 template <typename Char, if_compatible_char<Char> = true>
166 : m_data{str}, m_size{encodeType<Char>(str, len)}
167 {
168 }
169
170 template <typename Char, if_compatible_char<Char> = true>
171 constexpr QAnyStringView(const Char *f, const Char *l)
172 : QAnyStringView(f, l - f) {}
173
174#ifdef Q_QDOC
175 template <typename Char, size_t N>
176 constexpr QAnyStringView(const Char (&array)[N]) noexcept;
177
178 template <typename Char>
179 constexpr QAnyStringView(const Char *str) noexcept;
180#else
181
182 template <typename Pointer, if_compatible_pointer<Pointer> = true>
183 constexpr QAnyStringView(const Pointer &str) noexcept
184 : QAnyStringView{str, str ? lengthHelperPointer(str) : 0} {}
185#endif
186
187 // defined in qstring.h
188 inline QAnyStringView(const QByteArray &str) noexcept; // TODO: Should we have this at all? Remove?
189 inline QAnyStringView(const QString &str) noexcept;
190 inline constexpr QAnyStringView(QLatin1StringView str) noexcept;
191
192 template <typename Container, if_compatible_container<Container> = true>
193 constexpr Q_ALWAYS_INLINE QAnyStringView(const Container &c) noexcept
195
196 template <typename Container, if_convertible_to<QString, Container> = true>
198 //noexcept(std::is_nothrow_constructible_v<QString, Container>)
199 : QAnyStringView(capacity = std::forward<Container>(c)) {}
200
201 template <typename Container, if_convertible_to<QByteArray, Container> = true>
203 //noexcept(std::is_nothrow_constructible_v<QByteArray, Container>)
204 : QAnyStringView(capacity = std::forward<Container>(c)) {}
205 template <typename Char, if_compatible_char<Char> = true>
206 constexpr QAnyStringView(const Char &c) noexcept
207 : QAnyStringView{&c, 1} {}
208 template <typename Char, if_convertible_to<QChar, Char> = true>
209 constexpr QAnyStringView(Char ch, QCharContainer &&capacity = QCharContainer()) noexcept
210 : QAnyStringView{&(capacity.ch = ch), 1} {}
211
212 template <typename Char, typename Container = decltype(QChar::fromUcs4(U'x')),
213 std::enable_if_t<std::is_same_v<Char, char32_t>, bool> = true>
214 constexpr QAnyStringView(Char c, Container &&capacity = {}) noexcept
215 : QAnyStringView(capacity = QChar::fromUcs4(c)) {}
216
219
220 template <bool UseChar8T>
221 constexpr QAnyStringView(QBasicUtf8StringView<UseChar8T> v) noexcept
223
224 template <typename Char, size_t Size, if_compatible_char<Char> = true>
225 [[nodiscard]] constexpr static QAnyStringView fromArray(const Char (&string)[Size]) noexcept
226 { return QAnyStringView(string, Size); }
227
228 // defined in qstring.h:
229 template <typename Visitor>
230 inline constexpr decltype(auto) visit(Visitor &&v) const;
231
232 [[nodiscard]]
233 constexpr QAnyStringView mid(qsizetype pos, qsizetype n = -1) const
234 {
235 using namespace QtPrivate;
236 auto result = QContainerImplHelper::mid(size(), &pos, &n);
237 return result == QContainerImplHelper::Null ? QAnyStringView() : sliced(pos, n);
238 }
239 [[nodiscard]]
241 {
242 if (size_t(n) >= size_t(size()))
243 n = size();
244 return sliced(0, n);
245 }
246 [[nodiscard]]
248 {
249 if (size_t(n) >= size_t(size()))
250 n = size();
251 return sliced(size() - n, n);
252 }
253
254 [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos) const
255 { verify(pos, 0); auto r = *this; r.advanceData(pos); r.setSize(size() - pos); return r; }
256 [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos, qsizetype n) const
257 { verify(pos, n); auto r = *this; r.advanceData(pos); r.setSize(n); return r; }
258 [[nodiscard]] constexpr QAnyStringView first(qsizetype n) const
259 { verify(0, n); return sliced(0, n); }
260 [[nodiscard]] constexpr QAnyStringView last(qsizetype n) const
261 { verify(0, n); return sliced(size() - n, n); }
262 [[nodiscard]] constexpr QAnyStringView chopped(qsizetype n) const
263 { verify(0, n); return sliced(0, size() - n); }
264
265 constexpr void truncate(qsizetype n)
266 { verify(0, n); setSize(n); }
267 constexpr void chop(qsizetype n)
268 { verify(0, n); setSize(size() - n); }
269
270
271 [[nodiscard]] inline QString toString() const; // defined in qstring.h
272
273 [[nodiscard]] constexpr qsizetype size() const noexcept
274 { return qsizetype((m_size >> SizeShift) & SizeMask); }
275 [[nodiscard]] constexpr const void *data() const noexcept { return m_data; }
276
277 [[nodiscard]] Q_CORE_EXPORT static int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
278 [[nodiscard]] Q_CORE_EXPORT static bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept;
279
280 static constexpr inline bool detects_US_ASCII_at_compile_time =
281#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
282 true
283#else
284 false
285#endif
286 ;
287
288 //
289 // STL compatibility API:
290 //
291 [[nodiscard]] constexpr QChar front() const; // NOT noexcept!
292 [[nodiscard]] constexpr QChar back() const; // NOT noexcept!
293 [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
294 [[nodiscard]] constexpr qsizetype size_bytes() const noexcept
295 { return size() * charSize(); }
296
297 //
298 // Qt compatibility API:
299 //
300 [[nodiscard]] constexpr bool isNull() const noexcept { return !m_data; }
301 [[nodiscard]] constexpr bool isEmpty() const noexcept { return empty(); }
302 [[nodiscard]] constexpr qsizetype length() const noexcept
303 { return size(); }
304
305private:
306 friend bool comparesEqual(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
307 { return QAnyStringView::equal(lhs, rhs); }
309 compareThreeWay(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
310 {
311 const int res = QAnyStringView::compare(lhs, rhs);
312 return Qt::compareThreeWay(res, 0);
313 }
315
316#ifndef QT_NO_DEBUG_STREAM
317 Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s);
318#endif
319
320 [[nodiscard]] constexpr Tag tag() const noexcept { return Tag{m_size & TypeMask}; }
321 [[nodiscard]] constexpr bool isUtf16() const noexcept { return tag() == Tag::Utf16; }
322 [[nodiscard]] constexpr bool isUtf8() const noexcept { return tag() == Tag::Utf8; }
323 [[nodiscard]] constexpr bool isLatin1() const noexcept { return tag() == Tag::Latin1; }
324 [[nodiscard]] constexpr QStringView asStringView() const
325 { return Q_ASSERT(isUtf16()), QStringView{m_data_utf16, size()}; }
326 [[nodiscard]] constexpr q_no_char8_t::QUtf8StringView asUtf8StringView() const
327 { return Q_ASSERT(isUtf8()), q_no_char8_t::QUtf8StringView{m_data_utf8, size()}; }
328 [[nodiscard]] inline constexpr QLatin1StringView asLatin1StringView() const;
329 [[nodiscard]] constexpr size_t charSize() const noexcept { return isUtf16() ? 2 : 1; }
330 constexpr void setSize(qsizetype sz) noexcept { m_size = size_t(sz) | tag(); }
331 constexpr void advanceData(qsizetype delta) noexcept
332 { m_data_utf8 += delta * charSize(); }
333 Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
334 [[maybe_unused]] qsizetype n = 1) const
335 {
336 Q_ASSERT(pos >= 0);
337 Q_ASSERT(pos <= size());
338 Q_ASSERT(n >= 0);
339 Q_ASSERT(n <= size() - pos);
340 }
341 union {
342 const void *m_data;
343 const char *m_data_utf8;
344 const char16_t *m_data_utf16;
345 };
346 size_t m_size;
347 friend class ::tst_QAnyStringView;
348};
350
351template <typename QStringLike, std::enable_if_t<std::disjunction_v<
352 std::is_same<QStringLike, QString>,
353 std::is_same<QStringLike, QByteArray>
354 >, bool> = true>
355[[nodiscard]] inline QAnyStringView qToAnyStringViewIgnoringNull(const QStringLike &s) noexcept
356{ return QAnyStringView(s.begin(), s.size()); }
357
359
360#endif /* QANYSTRINGVIEW_H */
\inmodule QtCore
constexpr QAnyStringView(std::nullptr_t) noexcept
Constructs a null string view.
constexpr QAnyStringView() noexcept
Constructs a null string view.
constexpr QChar back() const
Returns the last character in the string view.
Definition qstring.h:122
constexpr QAnyStringView(Char c, Container &&capacity={}) noexcept
constexpr bool isNull() const noexcept
Returns whether this string view is null - that is, whether {data() == nullptr}.
Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s)
constexpr QAnyStringView sliced(qsizetype pos, qsizetype n) const
constexpr qsizetype size_bytes() const noexcept
Returns the size of this string view, but in bytes, not code-points.
static constexpr bool detects_US_ASCII_at_compile_time
qsizetype size_type
Alias for qsizetype.
constexpr qsizetype size() const noexcept
Returns the size of this string view, in the encoding's code points.
constexpr QAnyStringView(Char ch, QCharContainer &&capacity=QCharContainer()) noexcept
const char * m_data_utf8
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1218
static Q_CORE_EXPORT int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
Compares the string view lhs with the string view rhs and returns a negative integer if lhs is less t...
Definition qstring.cpp:1601
constexpr bool isEmpty() const noexcept
Returns whether this string view is empty - that is, whether {size() == 0}.
static constexpr QAnyStringView fromArray(const Char(&string)[Size]) noexcept
constexpr QAnyStringView right(qsizetype n) const
constexpr QAnyStringView(const Char &c) noexcept
static Q_CORE_EXPORT bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept
Definition qstring.cpp:1448
constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t< Container, QByteArray > &&capacity={})
constexpr QAnyStringView(const Char *f, const Char *l)
Constructs a string view on first with length (last - first).
friend bool comparesEqual(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
constexpr qsizetype length() const noexcept
Same as size().
const void * m_data
constexpr QAnyStringView last(qsizetype n) const
constexpr QAnyStringView sliced(qsizetype pos) const
constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t< Container, QString > &&capacity={})
const char16_t * m_data_utf16
qptrdiff difference_type
Alias for {std::ptrdiff_t}.
constexpr QChar front() const
Returns the first character in the string view.
Definition qstring.h:118
constexpr QAnyStringView left(qsizetype n) const
constexpr QAnyStringView(QStringView v) noexcept
constexpr QAnyStringView first(qsizetype n) const
constexpr QAnyStringView(const Char *str, qsizetype len)
Constructs a string view on str with length len.
constexpr QAnyStringView mid(qsizetype pos, qsizetype n=-1) const
constexpr QAnyStringView chopped(qsizetype n) const
constexpr void chop(qsizetype n)
constexpr const void * data() const noexcept
Returns a const pointer to the first character in the string view.
constexpr void truncate(qsizetype n)
constexpr Q_ALWAYS_INLINE QAnyStringView(const Container &c) noexcept
constexpr QAnyStringView(const Pointer &str) noexcept
friend Qt::strong_ordering compareThreeWay(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
constexpr QAnyStringView(QBasicUtf8StringView< UseChar8T > v) noexcept
constexpr bool empty() const noexcept
Returns whether this string view is empty - that is, whether {size() == 0}.
constexpr decltype(auto) visit(Visitor &&v) const
Calls v with either a QUtf8StringView, QLatin1String, or QStringView, depending on the encoding of th...
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore \title Classes and helpers for defining comparison operators \keyword qtcompare
Definition qcompare.h:403
QString str
[2]
Combined button and popup list for selecting options.
\macro QT_NO_KEYWORDS >
IsCompatiblePointer8Helper< q20::remove_cvref_t< Pointer > > IsCompatiblePointer8
constexpr Q_ALWAYS_INLINE std::enable_if_t< sizeof(Char)==sizeof(char16_t), qsizetype > lengthHelperContainer(const Char(&str)[N])
static constexpr qsizetype lengthHelperPointer(const Char *data) noexcept
IsCompatibleChar8TypeHelper< q20::remove_cvref_t< Char > > IsCompatibleChar8Type
typename wrapped< Tag, Result >::type wrapped_t
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype qustrlen(const char16_t *str) noexcept
Definition qstring.cpp:658
constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept
CaseSensitivity
@ CaseSensitive
constexpr bool is_constant_evaluated() noexcept
QAnyStringView qToAnyStringViewIgnoringNull(const QStringLike &s) noexcept
#define Q_DECLARE_STRONGLY_ORDERED(...)
#define Q_ALWAYS_INLINE
quint32 Tag
NSUInteger capacity
GLsizei const GLfloat * v
[13]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLfloat GLfloat f
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
GLuint res
const GLubyte * c
GLenum array
GLuint64EXT * result
[6]
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
char Char
#define Q_UNUSED(x)
@ Q_PRIMITIVE_TYPE
Definition qtypeinfo.h:154
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:177
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qptrdiff
Definition qtypes.h:164
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
\inmodule QtCore \reentrant
Definition qchar.h:18