1 | // Copyright (C) 2023 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QJSLIST_H |
5 | #define QJSLIST_H |
6 | |
7 | #include <QtQml/qtqmlglobal.h> |
8 | #include <QtQml/qqmllist.h> |
9 | #include <QtQml/qjsengine.h> |
10 | #include <QtCore/qobject.h> |
11 | #include <QtCore/qstring.h> |
12 | |
13 | #include <algorithm> |
14 | |
15 | // |
16 | // W A R N I N G |
17 | // ------------- |
18 | // |
19 | // This file is not part of the Qt API. It exists purely as an |
20 | // implementation detail. This header file may change from version to |
21 | // version. It will be kept compatible with the intended usage by |
22 | // code generated using qmlcachegen. |
23 | // |
24 | // We mean it. |
25 | // |
26 | |
27 | QT_BEGIN_NAMESPACE |
28 | |
29 | struct QJSListIndexClamp |
30 | { |
31 | static qsizetype clamp(qsizetype start, qsizetype max, qsizetype min = 0) |
32 | { |
33 | Q_ASSERT(min >= 0); |
34 | Q_ASSERT(min <= max); |
35 | return std::clamp(val: start < 0 ? max + qsizetype(start) : qsizetype(start), lo: min, hi: max); |
36 | } |
37 | }; |
38 | |
39 | template<typename List, typename Value = typename List::value_type> |
40 | struct QJSList : private QJSListIndexClamp |
41 | { |
42 | Q_DISABLE_COPY_MOVE(QJSList) |
43 | |
44 | QJSList(List *list, QJSEngine *engine) : m_list(list), m_engine(engine) {} |
45 | |
46 | Value at(qsizetype index) const |
47 | { |
48 | Q_ASSERT(index >= 0 && index < size()); |
49 | return *(m_list->cbegin() + index); |
50 | } |
51 | |
52 | qsizetype size() const { return m_list->size(); } |
53 | |
54 | void resize(qsizetype size) |
55 | { |
56 | m_list->resize(size); |
57 | } |
58 | |
59 | bool includes(const Value &value) const |
60 | { |
61 | return std::find(m_list->cbegin(), m_list->cend(), value) != m_list->cend(); |
62 | } |
63 | |
64 | bool includes(const Value &value, qsizetype start) const |
65 | { |
66 | return std::find(m_list->cbegin() + clamp(start, max: m_list->size()), m_list->cend(), value) |
67 | != m_list->cend(); |
68 | } |
69 | |
70 | QString join(const QString &separator = QStringLiteral(",")) const |
71 | { |
72 | QString result; |
73 | bool atBegin = true; |
74 | std::for_each(m_list->cbegin(), m_list->cend(), [&](const Value &value) { |
75 | if (atBegin) |
76 | atBegin = false; |
77 | else |
78 | result += separator; |
79 | result += m_engine->coerceValue<Value, QString>(value); |
80 | }); |
81 | return result; |
82 | } |
83 | |
84 | List slice() const |
85 | { |
86 | return *m_list; |
87 | } |
88 | List slice(qsizetype start) const |
89 | { |
90 | List result; |
91 | std::copy(m_list->cbegin() + clamp(start, max: m_list->size()), m_list->cend(), |
92 | std::back_inserter(result)); |
93 | return result; |
94 | } |
95 | List slice(qsizetype start, qsizetype end) const |
96 | { |
97 | const qsizetype size = m_list->size(); |
98 | const qsizetype clampedStart = clamp(start, max: size); |
99 | const qsizetype clampedEnd = clamp(start: end, max: size, min: clampedStart); |
100 | |
101 | List result; |
102 | std::copy(m_list->cbegin() + clampedStart, m_list->cbegin() + clampedEnd, |
103 | std::back_inserter(result)); |
104 | return result; |
105 | } |
106 | |
107 | qsizetype indexOf(const Value &value) const |
108 | { |
109 | const auto begin = m_list->cbegin(); |
110 | const auto end = m_list->cend(); |
111 | const auto it = std::find(begin, end, value); |
112 | if (it == end) |
113 | return -1; |
114 | const qsizetype result = it - begin; |
115 | Q_ASSERT(result >= 0); |
116 | return result; |
117 | } |
118 | qsizetype indexOf(const Value &value, qsizetype start) const |
119 | { |
120 | const auto begin = m_list->cbegin(); |
121 | const auto end = m_list->cend(); |
122 | const auto it = std::find(begin + clamp(start, max: m_list->size()), end, value); |
123 | if (it == end) |
124 | return -1; |
125 | const qsizetype result = it - begin; |
126 | Q_ASSERT(result >= 0); |
127 | return result; |
128 | } |
129 | |
130 | qsizetype lastIndexOf(const Value &value) const |
131 | { |
132 | const auto begin = std::make_reverse_iterator(m_list->cend()); |
133 | const auto end = std::make_reverse_iterator(m_list->cbegin()); |
134 | const auto it = std::find(begin, end, value); |
135 | return (end - it) - 1; |
136 | } |
137 | qsizetype lastIndexOf(const Value &value, qsizetype start) const |
138 | { |
139 | const qsizetype size = m_list->size(); |
140 | if (size == 0) |
141 | return -1; |
142 | |
143 | // Construct a one-past-end iterator as input. |
144 | const qsizetype clampedStart = std::min(a: clamp(start, max: size), b: size - 1); |
145 | const auto begin = std::make_reverse_iterator(m_list->cbegin() + clampedStart + 1); |
146 | |
147 | const auto end = std::make_reverse_iterator(m_list->cbegin()); |
148 | const auto it = std::find(begin, end, value); |
149 | return (end - it) - 1; |
150 | } |
151 | |
152 | QString toString() const { return join(); } |
153 | |
154 | private: |
155 | List *m_list = nullptr; |
156 | QJSEngine *m_engine = nullptr; |
157 | }; |
158 | |
159 | template<> |
160 | struct QJSList<QQmlListProperty<QObject>, QObject *> : private QJSListIndexClamp |
161 | { |
162 | Q_DISABLE_COPY_MOVE(QJSList) |
163 | |
164 | QJSList(QQmlListProperty<QObject> *list, QJSEngine *engine) : m_list(list), m_engine(engine) {} |
165 | |
166 | QObject *at(qsizetype index) const |
167 | { |
168 | Q_ASSERT(index >= 0 && index < size()); |
169 | return m_list->at(m_list, index); |
170 | } |
171 | |
172 | qsizetype size() const |
173 | { |
174 | return m_list->count(m_list); |
175 | } |
176 | |
177 | void resize(qsizetype size) |
178 | { |
179 | qsizetype current = m_list->count(m_list); |
180 | if (current < size && m_list->append) { |
181 | do { |
182 | m_list->append(m_list, nullptr); |
183 | } while (++current < size); |
184 | } else if (current > size && m_list->removeLast) { |
185 | do { |
186 | m_list->removeLast(m_list); |
187 | } while (--current > size); |
188 | } |
189 | } |
190 | |
191 | bool includes(const QObject *value) const |
192 | { |
193 | if (!m_list->count || !m_list->at) |
194 | return false; |
195 | |
196 | const qsizetype size = m_list->count(m_list); |
197 | for (qsizetype i = 0; i < size; ++i) { |
198 | if (m_list->at(m_list, i) == value) |
199 | return true; |
200 | } |
201 | |
202 | return false; |
203 | } |
204 | bool includes(const QObject *value, qsizetype start) const |
205 | { |
206 | if (!m_list->count || !m_list->at) |
207 | return false; |
208 | |
209 | const qsizetype size = m_list->count(m_list); |
210 | for (qsizetype i = clamp(start, max: size); i < size; ++i) { |
211 | if (m_list->at(m_list, i) == value) |
212 | return true; |
213 | } |
214 | |
215 | return false; |
216 | } |
217 | |
218 | QString join(const QString &separator = QStringLiteral(",")) const |
219 | { |
220 | if (!m_list->count || !m_list->at) |
221 | return QString(); |
222 | |
223 | QString result; |
224 | for (qsizetype i = 0, end = m_list->count(m_list); i < end; ++i) { |
225 | if (i != 0) |
226 | result += separator; |
227 | result += m_engine->coerceValue<QObject *, QString>(from: m_list->at(m_list, i)); |
228 | } |
229 | |
230 | return result; |
231 | } |
232 | |
233 | QObjectList slice() const |
234 | { |
235 | return m_list->toList<QObjectList>(); |
236 | } |
237 | QObjectList slice(qsizetype start) const |
238 | { |
239 | if (!m_list->count || !m_list->at) |
240 | return QObjectList(); |
241 | |
242 | const qsizetype size = m_list->count(m_list); |
243 | const qsizetype clampedStart = clamp(start, max: size); |
244 | QObjectList result; |
245 | result.reserve(asize: size - clampedStart); |
246 | for (qsizetype i = clampedStart; i < size; ++i) |
247 | result.append(t: m_list->at(m_list, i)); |
248 | return result; |
249 | } |
250 | QObjectList slice(qsizetype start, qsizetype end) const |
251 | { |
252 | if (!m_list->count || !m_list->at) |
253 | return QObjectList(); |
254 | |
255 | const qsizetype size = m_list->count(m_list); |
256 | const qsizetype clampedStart = clamp(start, max: size); |
257 | const qsizetype clampedEnd = clamp(start: end, max: size, min: clampedStart); |
258 | QObjectList result; |
259 | result.reserve(asize: clampedEnd - clampedStart); |
260 | for (qsizetype i = clampedStart; i < clampedEnd; ++i) |
261 | result.append(t: m_list->at(m_list, i)); |
262 | return result; |
263 | } |
264 | |
265 | qsizetype indexOf(const QObject *value) const |
266 | { |
267 | if (!m_list->count || !m_list->at) |
268 | return -1; |
269 | |
270 | const qsizetype end = m_list->count(m_list); |
271 | for (qsizetype i = 0; i < end; ++i) { |
272 | if (m_list->at(m_list, i) == value) |
273 | return i; |
274 | } |
275 | return -1; |
276 | } |
277 | qsizetype indexOf(const QObject *value, qsizetype start) const |
278 | { |
279 | if (!m_list->count || !m_list->at) |
280 | return -1; |
281 | |
282 | const qsizetype size = m_list->count(m_list); |
283 | for (qsizetype i = clamp(start, max: size); i < size; ++i) { |
284 | if (m_list->at(m_list, i) == value) |
285 | return i; |
286 | } |
287 | return -1; |
288 | } |
289 | |
290 | qsizetype lastIndexOf(const QObject *value) const |
291 | { |
292 | if (!m_list->count || !m_list->at) |
293 | return -1; |
294 | |
295 | for (qsizetype i = m_list->count(m_list) - 1; i >= 0; --i) { |
296 | if (m_list->at(m_list, i) == value) |
297 | return i; |
298 | } |
299 | return -1; |
300 | } |
301 | qsizetype lastIndexOf(const QObject *value, qsizetype start) const |
302 | { |
303 | if (!m_list->count || !m_list->at) |
304 | return -1; |
305 | |
306 | const qsizetype size = m_list->count(m_list); |
307 | if (size == 0) |
308 | return -1; |
309 | |
310 | qsizetype clampedStart = std::min(a: clamp(start, max: size), b: size - 1); |
311 | for (qsizetype i = clampedStart; i >= 0; --i) { |
312 | if (m_list->at(m_list, i) == value) |
313 | return i; |
314 | } |
315 | return -1; |
316 | } |
317 | |
318 | QString toString() const { return join(); } |
319 | |
320 | private: |
321 | QQmlListProperty<QObject> *m_list = nullptr; |
322 | QJSEngine *m_engine = nullptr; |
323 | }; |
324 | |
325 | struct QJSListForInIterator |
326 | { |
327 | public: |
328 | using Ptr = QJSListForInIterator *; |
329 | template<typename List, typename Value> |
330 | void init(const QJSList<List, Value> &list) |
331 | { |
332 | m_index = 0; |
333 | m_size = list.size(); |
334 | } |
335 | |
336 | bool hasNext() const { return m_index < m_size; } |
337 | qsizetype next() { return m_index++; } |
338 | |
339 | private: |
340 | qsizetype m_index; |
341 | qsizetype m_size; |
342 | }; |
343 | |
344 | // QJSListForInIterator must not require initialization so that we can jump over it with goto. |
345 | static_assert(std::is_trivial_v<QJSListForInIterator>); |
346 | |
347 | struct QJSListForOfIterator |
348 | { |
349 | public: |
350 | using Ptr = QJSListForOfIterator *; |
351 | void init() { m_index = 0; } |
352 | |
353 | template<typename List, typename Value> |
354 | bool hasNext(const QJSList<List, Value> &list) const { return m_index < list.size(); } |
355 | |
356 | template<typename List, typename Value> |
357 | Value next(const QJSList<List, Value> &list) { return list.at(m_index++); } |
358 | |
359 | private: |
360 | qsizetype m_index; |
361 | }; |
362 | |
363 | // QJSListForOfIterator must not require initialization so that we can jump over it with goto. |
364 | static_assert(std::is_trivial_v<QJSListForOfIterator>); |
365 | |
366 | QT_END_NAMESPACE |
367 | |
368 | #endif // QJSLIST_H |
369 |
Definitions
- QJSListIndexClamp
- clamp
- QJSList
- QJSList
- QJSList
- QJSList
- at
- size
- resize
- includes
- includes
- join
- slice
- slice
- slice
- indexOf
- indexOf
- lastIndexOf
- lastIndexOf
- toString
- QJSList
- QJSList
- QJSList
- at
- size
- resize
- includes
- includes
- join
- slice
- slice
- slice
- indexOf
- indexOf
- lastIndexOf
- lastIndexOf
- toString
- QJSListForInIterator
- init
- hasNext
- next
- QJSListForOfIterator
- init
- hasNext
Learn Advanced QML with KDAB
Find out more