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(int 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 bool includes(const Value &value) const
47 {
48 return std::find(m_list->cbegin(), m_list->cend(), value) != m_list->cend();
49 }
50
51 bool includes(const Value &value, int start) const
52 {
53 return std::find(m_list->cbegin() + clamp(start, max: m_list->size()), m_list->cend(), value)
54 != m_list->cend();
55 }
56
57 QString join(const QString &separator = QStringLiteral(",")) const
58 {
59 QString result;
60 bool atBegin = true;
61 std::for_each(m_list->cbegin(), m_list->cend(), [&](const Value &value) {
62 if (atBegin)
63 atBegin = false;
64 else
65 result += separator;
66 result += m_engine->coerceValue<Value, QString>(value);
67 });
68 return result;
69 }
70
71 List slice() const
72 {
73 return *m_list;
74 }
75 List slice(int start) const
76 {
77 List result;
78 std::copy(m_list->cbegin() + clamp(start, max: m_list->size()), m_list->cend(),
79 std::back_inserter(result));
80 return result;
81 }
82 List slice(int start, int end) const
83 {
84 const qsizetype size = m_list->size();
85 const qsizetype clampedStart = clamp(start, max: size);
86 const qsizetype clampedEnd = clamp(start: end, max: size, min: clampedStart);
87
88 List result;
89 std::copy(m_list->cbegin() + clampedStart, m_list->cbegin() + clampedEnd,
90 std::back_inserter(result));
91 return result;
92 }
93
94 int indexOf(const Value &value) const
95 {
96 const auto begin = m_list->cbegin();
97 const auto end = m_list->cend();
98 const auto it = std::find(begin, end, value);
99 if (it == end)
100 return -1;
101 const qsizetype result = it - begin;
102 Q_ASSERT(result >= 0);
103 return result > std::numeric_limits<int>::max() ? -1 : int(result);
104 }
105 int indexOf(const Value &value, int start) const
106 {
107 const auto begin = m_list->cbegin();
108 const auto end = m_list->cend();
109 const auto it = std::find(begin + clamp(start, max: m_list->size()), end, value);
110 if (it == end)
111 return -1;
112 const qsizetype result = it - begin;
113 Q_ASSERT(result >= 0);
114 return result > std::numeric_limits<int>::max() ? -1 : int(result);
115 }
116
117 int lastIndexOf(const Value &value) const
118 {
119 const auto begin = std::make_reverse_iterator(m_list->cend());
120 const auto end = std::make_reverse_iterator(m_list->cbegin());
121 const auto it = std::find(begin, end, value);
122 const qsizetype result = (end - it) - 1;
123 return result > std::numeric_limits<int>::max() ? -1 : int(result);
124 }
125 int lastIndexOf(const Value &value, int start) const
126 {
127 const qsizetype size = m_list->size();
128 if (size == 0)
129 return -1;
130
131 // Construct a one-past-end iterator as input.
132 const qsizetype clampedStart = std::min(a: clamp(start, max: size), b: size - 1);
133 const auto begin = std::make_reverse_iterator(m_list->cbegin() + clampedStart + 1);
134
135 const auto end = std::make_reverse_iterator(m_list->cbegin());
136 const auto it = std::find(begin, end, value);
137 const qsizetype result = (end - it) - 1;
138 return result > std::numeric_limits<int>::max() ? -1 : int(result);
139 }
140
141 QString toString() const { return join(); }
142
143private:
144 List *m_list = nullptr;
145 QJSEngine *m_engine = nullptr;
146};
147
148template<>
149struct QJSList<QQmlListProperty<QObject>, QObject *> : private QJSListIndexClamp
150{
151 Q_DISABLE_COPY_MOVE(QJSList)
152
153 QJSList(QQmlListProperty<QObject> *list, QJSEngine *engine) : m_list(list), m_engine(engine) {}
154
155 bool includes(const QObject *value) const
156 {
157 if (!m_list->count || !m_list->at)
158 return false;
159
160 const qsizetype size = m_list->count(m_list);
161 for (qsizetype i = 0; i < size; ++i) {
162 if (m_list->at(m_list, i) == value)
163 return true;
164 }
165
166 return false;
167 }
168 bool includes(const QObject *value, int start) const
169 {
170 if (!m_list->count || !m_list->at)
171 return false;
172
173 const qsizetype size = m_list->count(m_list);
174 for (qsizetype i = clamp(start, max: size); i < size; ++i) {
175 if (m_list->at(m_list, i) == value)
176 return true;
177 }
178
179 return false;
180 }
181
182 QString join(const QString &separator = QStringLiteral(",")) const
183 {
184 if (!m_list->count || !m_list->at)
185 return QString();
186
187 QString result;
188 for (qsizetype i = 0, end = m_list->count(m_list); i < end; ++i) {
189 if (i != 0)
190 result += separator;
191 result += m_engine->coerceValue<QObject *, QString>(from: m_list->at(m_list, i));
192 }
193
194 return result;
195 }
196
197 QObjectList slice() const
198 {
199 return m_list->toList<QObjectList>();
200 }
201 QObjectList slice(int start) const
202 {
203 if (!m_list->count || !m_list->at)
204 return QObjectList();
205
206 const qsizetype size = m_list->count(m_list);
207 const qsizetype clampedStart = clamp(start, max: size);
208 QObjectList result;
209 result.reserve(asize: size - clampedStart);
210 for (qsizetype i = clampedStart; i < size; ++i)
211 result.append(t: m_list->at(m_list, i));
212 return result;
213 }
214 QObjectList slice(int start, int end) const
215 {
216 if (!m_list->count || !m_list->at)
217 return QObjectList();
218
219 const qsizetype size = m_list->count(m_list);
220 const qsizetype clampedStart = clamp(start, max: size);
221 const qsizetype clampedEnd = clamp(start: end, max: size, min: clampedStart);
222 QObjectList result;
223 result.reserve(asize: clampedEnd - clampedStart);
224 for (qsizetype i = clampedStart; i < clampedEnd; ++i)
225 result.append(t: m_list->at(m_list, i));
226 return result;
227 }
228
229 int indexOf(const QObject *value) const
230 {
231 if (!m_list->count || !m_list->at)
232 return -1;
233
234 const qsizetype end
235 = std::min(a: m_list->count(m_list), b: qsizetype(std::numeric_limits<int>::max()));
236 for (qsizetype i = 0; i < end; ++i) {
237 if (m_list->at(m_list, i) == value)
238 return int(i);
239 }
240 return -1;
241 }
242 int indexOf(const QObject *value, int start) const
243 {
244 if (!m_list->count || !m_list->at)
245 return -1;
246
247 const qsizetype size = m_list->count(m_list);
248 for (qsizetype i = clamp(start, max: size),
249 end = std::min(a: size, b: qsizetype(std::numeric_limits<int>::max()));
250 i < end; ++i) {
251 if (m_list->at(m_list, i) == value)
252 return int(i);
253 }
254 return -1;
255 }
256
257 int lastIndexOf(const QObject *value) const
258 {
259 if (!m_list->count || !m_list->at)
260 return -1;
261
262 for (qsizetype i = m_list->count(m_list) - 1; i >= 0; --i) {
263 if (m_list->at(m_list, i) == value)
264 return i > std::numeric_limits<int>::max() ? -1 : int(i);
265 }
266 return -1;
267 }
268 int lastIndexOf(const QObject *value, int start) const
269 {
270 if (!m_list->count || !m_list->at)
271 return -1;
272
273 const qsizetype size = m_list->count(m_list);
274 if (size == 0)
275 return -1;
276
277 qsizetype clampedStart = std::min(a: clamp(start, max: size), b: size - 1);
278 for (qsizetype i = clampedStart; i >= 0; --i) {
279 if (m_list->at(m_list, i) == value)
280 return i > std::numeric_limits<int>::max() ? -1 : int(i);
281 }
282 return -1;
283 }
284
285 QString toString() const { return join(); }
286
287private:
288 QQmlListProperty<QObject> *m_list = nullptr;
289 QJSEngine *m_engine = nullptr;
290};
291
292QT_END_NAMESPACE
293
294#endif // QJSLIST_H
295

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