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
27QT_BEGIN_NAMESPACE
28
29struct 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
39template<typename List, typename Value = typename List::value_type>
40struct 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
154private:
155 List *m_list = nullptr;
156 QJSEngine *m_engine = nullptr;
157};
158
159template<>
160struct 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
320private:
321 QQmlListProperty<QObject> *m_list = nullptr;
322 QJSEngine *m_engine = nullptr;
323};
324
325struct QJSListForInIterator
326{
327public:
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
339private:
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.
345static_assert(std::is_trivial_v<QJSListForInIterator>);
346
347struct QJSListForOfIterator
348{
349public:
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
359private:
360 qsizetype m_index;
361};
362
363// QJSListForOfIterator must not require initialization so that we can jump over it with goto.
364static_assert(std::is_trivial_v<QJSListForOfIterator>);
365
366QT_END_NAMESPACE
367
368#endif // QJSLIST_H
369

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/qml/jsapi/qjslist.h