Qt 6.x
The Qt SDK
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/qlatin1stringview.h>
8#include <QtCore/qstringview.h>
9#include <QtCore/qutf8stringview.h>
10
11#ifdef __cpp_impl_three_way_comparison
12#include <compare>
13#endif
14#include <QtCore/q20type_traits.h>
15#include <limits>
16
17class tst_QAnyStringView;
18
20
21namespace QtPrivate {
22
23template <typename Tag, typename Result>
24struct wrapped { using type = Result; };
25
26template <typename Tag, typename Result>
28
29} // namespace QtPrivate
30
32{
33public:
36private:
37 static constexpr size_t SizeMask = (std::numeric_limits<size_t>::max)() / 4;
38#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED)
39 static constexpr int SizeShift = 2;
40 static constexpr size_t Latin1Flag = 1;
41#else
42 static constexpr int SizeShift = 0;
43 static constexpr size_t Latin1Flag = SizeMask + 1;
44#endif
45 static constexpr size_t TwoByteCodePointFlag = Latin1Flag << 1;
46 static constexpr size_t TypeMask = ~(SizeMask << SizeShift);
47 static_assert(TypeMask == (Latin1Flag|TwoByteCodePointFlag));
48
49 // Tag bits
50 // 0 0 Utf8
51 // 0 1 Latin1
52 // 1 0 Utf16
53 // 1 1 Unused
54 // ^ ^ latin1
55 // | sizeof code-point == 2
56 enum Tag : size_t {
57 Utf8 = 0,
58 Latin1 = Latin1Flag,
59 Utf16 = TwoByteCodePointFlag,
60 Unused = TypeMask,
61 };
62
63 template <typename Char>
64 using if_compatible_char = std::enable_if_t<std::disjunction_v<
67 >, bool>;
68
69 template <typename Pointer>
70 using if_compatible_pointer = std::enable_if_t<std::disjunction_v<
73 >, bool>;
74
75
76 template <typename T>
77 using if_compatible_container = std::enable_if_t<std::disjunction_v<
80 >, bool>;
81
82 template <typename QStringOrQByteArray, typename T>
83 using if_convertible_to = std::enable_if_t<std::conjunction_v<
84 // need to exclude a bunch of stuff, because we take by universal reference:
85 std::negation<std::disjunction<
86 std::is_same<q20::remove_cvref_t<T>, QAnyStringView::Tag>,
87 std::is_same<q20::remove_cvref_t<T>, QAnyStringView>, // don't make a copy/move ctor
88 std::is_pointer<std::decay_t<T>>, // const char*, etc
89 std::is_same<q20::remove_cvref_t<T>, QByteArray>,
90 std::is_same<q20::remove_cvref_t<T>, QString>
91 >>,
92 // this is what we're really after:
93 std::is_convertible<T, QStringOrQByteArray>
94 >, bool>;
95
96 // confirm we don't make an accidental copy constructor:
99
100 template<typename Char>
101 static constexpr bool isAsciiOnlyCharsAtCompileTime(Char *str, qsizetype sz) noexcept
102 {
103 // do not perform check if not at compile time
104#if !defined(QT_SUPPORTS_IS_CONSTANT_EVALUATED)
105 Q_UNUSED(str);
106 Q_UNUSED(sz);
107 return false;
108#else
109 if (!qIsConstantEvaluated())
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#endif
123 }
124
125 template<typename Char>
126 static constexpr std::size_t encodeType(const Char *str, qsizetype sz) noexcept
127 {
128 // Utf16 if 16 bit, Latin1 if ASCII, else Utf8
129 Q_ASSERT(sz >= 0);
130 Q_ASSERT(sz <= qsizetype(SizeMask));
131 Q_ASSERT(str || !sz);
132 return (std::size_t(sz) << SizeShift)
133 | uint(sizeof(Char) == sizeof(char16_t)) * Tag::Utf16
134 | uint(isAsciiOnlyCharsAtCompileTime(str, sz)) * Tag::Latin1;
135 }
136
137 template <typename Char>
138 static constexpr qsizetype lengthHelperPointer(const Char *str) noexcept
139 {
140#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
141 if (qIsConstantEvaluated())
142 return qsizetype(std::char_traits<Char>::length(str));
143#endif
144 if constexpr (sizeof(Char) == sizeof(char16_t))
145 return QtPrivate::qustrlen(reinterpret_cast<const char16_t*>(str));
146 else
147 return qsizetype(strlen(reinterpret_cast<const char*>(str)));
148 }
149
150 static QChar toQChar(char ch) noexcept { return toQChar(QLatin1Char{ch}); } // we don't handle UTF-8 multibytes
151 static QChar toQChar(QChar ch) noexcept { return ch; }
152 static QChar toQChar(QLatin1Char ch) noexcept { return ch; }
153
154 explicit constexpr QAnyStringView(const void *d, qsizetype n, std::size_t sizeAndType) noexcept
155 : m_data{d}, m_size{std::size_t(n) | (sizeAndType & TypeMask)} {}
156public:
157 constexpr QAnyStringView() noexcept
158 : m_data{nullptr}, m_size{0} {}
159 constexpr QAnyStringView(std::nullptr_t) noexcept
160 : QAnyStringView() {}
161
162 template <typename Char, if_compatible_char<Char> = true>
164 : m_data{str}, m_size{encodeType<Char>(str, len)}
165 {
166 }
167
168 template <typename Char, if_compatible_char<Char> = true>
169 constexpr QAnyStringView(const Char *f, const Char *l)
170 : QAnyStringView(f, l - f) {}
171
172#ifdef Q_QDOC
173 template <typename Char, size_t N>
174 constexpr QAnyStringView(const Char (&array)[N]) noexcept;
175
176 template <typename Char>
177 constexpr QAnyStringView(const Char *str) noexcept;
178#else
179
180 template <typename Pointer, if_compatible_pointer<Pointer> = true>
181 constexpr QAnyStringView(const Pointer &str) noexcept
182 : QAnyStringView{str, str ? lengthHelperPointer(str) : 0} {}
183#endif
184
185 // defined in qstring.h
186 inline QAnyStringView(const QByteArray &str) noexcept; // TODO: Should we have this at all? Remove?
187 inline QAnyStringView(const QString &str) noexcept;
188 inline constexpr QAnyStringView(QLatin1StringView str) noexcept;
189
190 template <typename Container, if_compatible_container<Container> = true>
191 constexpr Q_ALWAYS_INLINE QAnyStringView(const Container &c) noexcept
193
194 template <typename Container, if_convertible_to<QString, Container> = true>
196 //noexcept(std::is_nothrow_constructible_v<QString, Container>)
197 : QAnyStringView(capacity = std::forward<Container>(c)) {}
198
199 template <typename Container, if_convertible_to<QByteArray, Container> = true>
201 //noexcept(std::is_nothrow_constructible_v<QByteArray, Container>)
202 : QAnyStringView(capacity = std::forward<Container>(c)) {}
203
204 template <typename Char, if_compatible_char<Char> = true>
205 constexpr QAnyStringView(const Char &c) noexcept
206 : QAnyStringView{&c, 1} {}
207 constexpr QAnyStringView(const QChar &c) noexcept
208 : QAnyStringView{&c, 1} {}
209
210 template <typename Char, typename Container = decltype(QChar::fromUcs4(U'x')),
211 std::enable_if_t<std::is_same_v<Char, char32_t>, bool> = true>
212 constexpr QAnyStringView(Char c, Container &&capacity = {})
213 : QAnyStringView(capacity = QChar::fromUcs4(c)) {}
214
215 constexpr QAnyStringView(QStringView v) noexcept
217
218 template <bool UseChar8T>
221
222 template <typename Char, size_t Size, if_compatible_char<Char> = true>
223 [[nodiscard]] constexpr static QAnyStringView fromArray(const Char (&string)[Size]) noexcept
224 { return QAnyStringView(string, Size); }
225
226 // defined in qstring.h:
227 template <typename Visitor>
228 inline constexpr decltype(auto) visit(Visitor &&v) const;
229
230 [[nodiscard]]
231 constexpr QAnyStringView mid(qsizetype pos, qsizetype n = -1) const
232 {
233 using namespace QtPrivate;
234 auto result = QContainerImplHelper::mid(size(), &pos, &n);
235 return result == QContainerImplHelper::Null ? QAnyStringView() : sliced(pos, n);
236 }
237 [[nodiscard]]
239 {
240 if (size_t(n) >= size_t(size()))
241 n = size();
242 return sliced(0, n);
243 }
244 [[nodiscard]]
246 {
247 if (size_t(n) >= size_t(size()))
248 n = size();
249 return sliced(size() - n, n);
250 }
251
252 [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos) const
253 { verify(pos); auto r = *this; r.advanceData(pos); r.setSize(size() - pos); return r; }
254 [[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos, qsizetype n) const
255 { verify(pos, n); auto r = *this; r.advanceData(pos); r.setSize(n); return r; }
256 [[nodiscard]] constexpr QAnyStringView first(qsizetype n) const
257 { verify(n); return sliced(0, n); }
258 [[nodiscard]] constexpr QAnyStringView last(qsizetype n) const
259 { verify(n); return sliced(size() - n, n); }
260 [[nodiscard]] constexpr QAnyStringView chopped(qsizetype n) const
261 { verify(n); return sliced(0, size() - n); }
262
263 constexpr void truncate(qsizetype n)
264 { verify(n); setSize(n); }
265 constexpr void chop(qsizetype n)
266 { verify(n); setSize(size() - n); }
267
268
269 [[nodiscard]] inline QString toString() const; // defined in qstring.h
270
271 [[nodiscard]] constexpr qsizetype size() const noexcept
272 { return qsizetype((m_size >> SizeShift) & SizeMask); }
273 [[nodiscard]] constexpr const void *data() const noexcept { return m_data; }
274
275 [[nodiscard]] Q_CORE_EXPORT static int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
276 [[nodiscard]] Q_CORE_EXPORT static bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept;
277
278 //
279 // STL compatibility API:
280 //
281 [[nodiscard]] constexpr QChar front() const; // NOT noexcept!
282 [[nodiscard]] constexpr QChar back() const; // NOT noexcept!
283 [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
284 [[nodiscard]] constexpr qsizetype size_bytes() const noexcept
285 { return size() * charSize(); }
286
287 //
288 // Qt compatibility API:
289 //
290 [[nodiscard]] constexpr bool isNull() const noexcept { return !m_data; }
291 [[nodiscard]] constexpr bool isEmpty() const noexcept { return empty(); }
292 [[nodiscard]] constexpr qsizetype length() const noexcept
293 { return size(); }
294
295private:
296 [[nodiscard]] friend inline bool operator==(QAnyStringView lhs, QAnyStringView rhs) noexcept
297 { return QAnyStringView::equal(lhs, rhs); }
298 [[nodiscard]] friend inline bool operator!=(QAnyStringView lhs, QAnyStringView rhs) noexcept
299 { return !QAnyStringView::equal(lhs, rhs); }
300
301#if defined(__cpp_impl_three_way_comparison) && !defined(Q_QDOC)
302 [[nodiscard]] friend inline auto operator<=>(QAnyStringView lhs, QAnyStringView rhs) noexcept
303 { return QAnyStringView::compare(lhs, rhs) <=> 0; }
304#else
305 [[nodiscard]] friend inline bool operator<=(QAnyStringView lhs, QAnyStringView rhs) noexcept
306 { return QAnyStringView::compare(lhs, rhs) <= 0; }
307 [[nodiscard]] friend inline bool operator>=(QAnyStringView lhs, QAnyStringView rhs) noexcept
308 { return QAnyStringView::compare(lhs, rhs) >= 0; }
309 [[nodiscard]] friend inline bool operator<(QAnyStringView lhs, QAnyStringView rhs) noexcept
310 { return QAnyStringView::compare(lhs, rhs) < 0; }
311 [[nodiscard]] friend inline bool operator>(QAnyStringView lhs, QAnyStringView rhs) noexcept
312 { return QAnyStringView::compare(lhs, rhs) > 0; }
313#endif
314
315#ifndef QT_NO_DEBUG_STREAM
316 Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s);
317#endif
318
319 [[nodiscard]] constexpr Tag tag() const noexcept { return Tag{m_size & TypeMask}; }
320 [[nodiscard]] constexpr bool isUtf16() const noexcept { return tag() == Tag::Utf16; }
321 [[nodiscard]] constexpr bool isUtf8() const noexcept { return tag() == Tag::Utf8; }
322 [[nodiscard]] constexpr bool isLatin1() const noexcept { return tag() == Tag::Latin1; }
323 [[nodiscard]] constexpr QStringView asStringView() const
324 { return Q_ASSERT(isUtf16()), QStringView{m_data_utf16, size()}; }
325 [[nodiscard]] constexpr q_no_char8_t::QUtf8StringView asUtf8StringView() const
326 { return Q_ASSERT(isUtf8()), q_no_char8_t::QUtf8StringView{m_data_utf8, size()}; }
327 [[nodiscard]] inline constexpr QLatin1StringView asLatin1StringView() const;
328 [[nodiscard]] constexpr size_t charSize() const noexcept { return isUtf16() ? 2 : 1; }
329 constexpr void setSize(qsizetype sz) noexcept { m_size = size_t(sz) | tag(); }
330 constexpr void advanceData(qsizetype delta) noexcept
331 { m_data_utf8 += delta * charSize(); }
332 Q_ALWAYS_INLINE constexpr void verify(qsizetype pos, qsizetype n = 0) const
333 {
334 Q_ASSERT(pos >= 0);
335 Q_ASSERT(pos <= size());
336 Q_ASSERT(n >= 0);
337 Q_ASSERT(n <= size() - pos);
338 }
339 union {
340 const void *m_data;
341 const char *m_data_utf8;
342 const char16_t *m_data_utf16;
343 };
344 size_t m_size;
345 friend class ::tst_QAnyStringView;
346};
348
349template <typename QStringLike, std::enable_if_t<std::disjunction_v<
350 std::is_same<QStringLike, QString>,
351 std::is_same<QStringLike, QByteArray>
352 >, bool> = true>
353[[nodiscard]] inline QAnyStringView qToAnyStringViewIgnoringNull(const QStringLike &s) noexcept
354{ return QAnyStringView(s.data(), s.size()); }
355
357
358#endif /* QANYSTRINGVIEW_H */
\inmodule QtCore
constexpr QAnyStringView(const QChar &c) noexcept
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:120
constexpr bool isNull() const noexcept
Returns whether this string view is null - that is, whether {data() == nullptr}.
constexpr QAnyStringView(const Char *str, qsizetype len)
Constructs a string view on str with length len.
friend bool operator>=(QAnyStringView lhs, QAnyStringView rhs) noexcept
constexpr qsizetype size_bytes() const noexcept
Returns the size of this string view, but in bytes, not code-points.
qsizetype size_type
Alias for qsizetype.
friend bool operator<=(QAnyStringView lhs, QAnyStringView rhs) noexcept
constexpr qsizetype size() const noexcept
Returns the size of this string view, in the encoding's code points.
constexpr QAnyStringView sliced(qsizetype pos, qsizetype n) const
constexpr QAnyStringView sliced(qsizetype pos) const
const char * m_data_utf8
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1071
friend bool operator==(QAnyStringView lhs, QAnyStringView rhs) noexcept
friend bool operator!=(QAnyStringView lhs, QAnyStringView rhs) noexcept
static Q_CORE_EXPORT int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
Returns an integer that compares to zero as lhs compares to rhs.
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:1450
constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t< Container, QByteArray > &&capacity={})
Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s)
constexpr qsizetype length() const noexcept
Same as size().
const void * m_data
constexpr QAnyStringView last(qsizetype n) 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}.
friend bool operator>(QAnyStringView lhs, QAnyStringView rhs) noexcept
Operators that compare lhs to rhs.
constexpr QChar front() const
Returns the first character in the string view.
Definition qstring.h:116
constexpr QAnyStringView left(qsizetype n) const
constexpr QAnyStringView(QStringView v) noexcept
constexpr QAnyStringView first(qsizetype n) const
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 QAnyStringView(Char c, Container &&capacity={})
friend bool operator<(QAnyStringView lhs, QAnyStringView rhs) noexcept
constexpr QAnyStringView(const Char *f, const Char *l)
Constructs a string view on first with length (last - first).
constexpr Q_ALWAYS_INLINE QAnyStringView(const Container &c) noexcept
constexpr QAnyStringView(const Pointer &str) 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
Definition qchar.h:48
static constexpr auto fromUcs4(char32_t c) noexcept
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString str
[2]
Combined button and popup list for selecting options.
\macro QT_NAMESPACE
constexpr Q_ALWAYS_INLINE std::enable_if_t< sizeof(Char)==sizeof(char16_t), qsizetype > lengthHelperContainer(const Char(&str)[N])
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype qustrlen(const char16_t *str) noexcept
Definition qstring.cpp:686
IsCompatibleChar8TypeHelper< q20::remove_cvref_t< Char > > IsCompatibleChar8Type
typename wrapped< Tag, Result >::type wrapped_t
CaseSensitivity
@ CaseSensitive
QAnyStringView qToAnyStringViewIgnoringNull(const QStringLike &s) noexcept
#define Q_ALWAYS_INLINE
NSUInteger capacity
#define Size(name)
GLsizei const GLfloat * v
[13]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLfloat GLfloat f
GLfloat n
const GLubyte * c
GLenum array
GLenum GLsizei len
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
char Char
#define Q_UNUSED(x)
Tag
@ Q_PRIMITIVE_TYPE
Definition qtypeinfo.h:144
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:163
unsigned char uchar
Definition qtypes.h:27
ptrdiff_t qptrdiff
Definition qtypes.h:69
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
\inmodule QtCore \reentrant
Definition qchar.h:17