1// Copyright (C) 2016 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 QQMLLISTCOMPOSITOR_P_H
5#define QQMLLISTCOMPOSITOR_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/qglobal.h>
19#include <QtCore/qvector.h>
20
21#include <private/qqmlchangeset_p.h>
22
23#include <QtCore/qdebug.h>
24
25QT_BEGIN_NAMESPACE
26
27class Q_AUTOTEST_EXPORT QQmlListCompositor
28{
29public:
30 enum { MinimumGroupCount = 3, MaximumGroupCount = 11 };
31
32 enum Group
33 {
34 Cache = 0,
35 Default = 1,
36 Persisted = 2
37 };
38
39 enum Flag
40 {
41 CacheFlag = 1 << Cache,
42 DefaultFlag = 1 << Default,
43 PersistedFlag = 1 << Persisted,
44 PrependFlag = 0x10000000,
45 AppendFlag = 0x20000000,
46 UnresolvedFlag = 0x40000000,
47 MovedFlag = 0x80000000,
48 GroupMask = ~(PrependFlag | AppendFlag | UnresolvedFlag | MovedFlag | CacheFlag)
49 };
50
51 class Range
52 {
53 public:
54 Range() : next(this), previous(this) {}
55 Range(Range *next, void *list, int index, int count, uint flags)
56 : next(next), previous(next->previous), list(list), index(index), count(count), flags(flags) {
57 next->previous = this; previous->next = this; }
58
59 Range *next;
60 Range *previous;
61 void *list = nullptr;
62 int index = 0;
63 int count = 0;
64 uint flags = 0;
65
66 inline int start() const { return index; }
67 inline int end() const { return index + count; }
68
69 inline int groups() const { return flags & GroupMask; }
70
71 inline bool inGroup() const { return flags & GroupMask; }
72 inline bool inCache() const { return flags & CacheFlag; }
73 inline bool inGroup(int group) const { return flags & (1 << group); }
74 inline bool isUnresolved() const { return flags & UnresolvedFlag; }
75
76 inline bool prepend() const { return flags & PrependFlag; }
77 inline bool append() const { return flags & AppendFlag; }
78 };
79
80 class Q_AUTOTEST_EXPORT iterator
81 {
82 public:
83 inline iterator() = default;
84 inline iterator(Range *range, int offset, Group group, int groupCount);
85
86 bool operator ==(const iterator &it) const { return range == it.range && offset == it.offset; }
87 bool operator !=(const iterator &it) const { return range != it.range || offset != it.offset; }
88
89 bool operator ==(Group group) const { return range->flags & (1 << group); }
90 bool operator !=(Group group) const { return !(range->flags & (1 << group)); }
91
92 Range *&operator *() { return range; }
93 Range * const &operator *() const { return range; }
94 Range *operator ->() { return range; }
95 const Range *operator ->() const { return range; }
96
97 iterator &operator +=(int difference);
98
99 template<typename T> T *list() const { return static_cast<T *>(range->list); }
100 int modelIndex() const { return range->index + offset; }
101
102 void incrementIndexes(int difference) { incrementIndexes(difference, flags: range->flags); }
103 void decrementIndexes(int difference) { decrementIndexes(difference, flags: range->flags); }
104
105 inline void incrementIndexes(int difference, uint flags);
106 inline void decrementIndexes(int difference, uint flags);
107
108 void setGroup(Group g) { group = g; groupFlag = 1 << g; }
109
110 Range *range = nullptr;
111 int offset = 0;
112 Group group = Default;
113 int groupFlag = 0;
114 int groupCount = 0;
115 int index[MaximumGroupCount] = { 0 };
116
117 int cacheIndex() const {
118 return index[Cache];
119 }
120
121 void setCacheIndex(int cacheIndex) {
122 index[Cache] = cacheIndex;
123 }
124 };
125
126 class Q_AUTOTEST_EXPORT insert_iterator : public iterator
127 {
128 public:
129 inline insert_iterator() {}
130 inline insert_iterator(const iterator &it) : iterator(it) {}
131 inline insert_iterator(Range *, int, Group, int);
132
133 insert_iterator &operator +=(int difference);
134 };
135
136 struct Change
137 {
138 inline Change() = default;
139 inline Change(const iterator &it, int count, uint flags, int moveId = -1);
140 int count = 0;
141 uint flags = 0;
142 int moveId = 0;
143 int index[MaximumGroupCount] = { 0 };
144
145 int cacheIndex() const {
146 return index[Cache];
147 }
148
149 void setCacheIndex(int cacheIndex) {
150 index[Cache] = cacheIndex;
151 }
152
153 inline bool isMove() const { return moveId >= 0; }
154 inline bool inCache() const { return flags & CacheFlag; }
155 inline bool inGroup() const { return flags & GroupMask; }
156 inline bool inGroup(int group) const { return flags & (CacheFlag << group); }
157
158 inline int groups() const { return flags & GroupMask; }
159 };
160
161 struct Insert : public Change
162 {
163 Insert() {}
164 Insert(const iterator &it, int count, uint flags, int moveId = -1)
165 : Change(it, count, flags, moveId) {}
166 };
167
168 struct Remove : public Change
169 {
170 Remove() {}
171 Remove(const iterator &it, int count, uint flags, int moveId = -1)
172 : Change(it, count, flags, moveId) {}
173 };
174
175 QQmlListCompositor();
176 ~QQmlListCompositor();
177
178 int defaultGroups() const { return m_defaultFlags & ~PrependFlag; }
179 void setDefaultGroups(int groups) { m_defaultFlags = groups | PrependFlag; }
180 void setDefaultGroup(Group group) { m_defaultFlags |= (1 << group); }
181 void clearDefaultGroup(Group group) { m_defaultFlags &= ~(1 << group); }
182 void setRemoveGroups(int groups) { m_removeFlags = PrependFlag | AppendFlag | groups; }
183 void setGroupCount(int count);
184
185 int count(Group group) const;
186 iterator find(Group group, int index);
187 iterator find(Group group, int index) const;
188 insert_iterator findInsertPosition(Group group, int index);
189
190 const iterator &end() { return m_end; }
191
192 void append(void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
193 void insert(Group group, int before, void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
194 iterator insert(iterator before, void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
195
196 void setFlags(Group fromGroup, int from, int count, Group group, int flags, QVector<Insert> *inserts = nullptr);
197 void setFlags(iterator from, int count, Group group, uint flags, QVector<Insert> *inserts = nullptr);
198 void setFlags(Group fromGroup, int from, int count, uint flags, QVector<Insert> *inserts = nullptr) {
199 setFlags(fromGroup, from, count, group: fromGroup, flags, inserts); }
200 void setFlags(const iterator from, int count, uint flags, QVector<Insert> *inserts = nullptr) {
201 setFlags(from, count, group: from.group, flags, inserts); }
202
203 void clearFlags(Group fromGroup, int from, int count, Group group, uint flags, QVector<Remove> *removals = nullptr);
204 void clearFlags(iterator from, int count, Group group, uint flags, QVector<Remove> *removals = nullptr);
205 void clearFlags(Group fromGroup, int from, int count, uint flags, QVector<Remove> *removals = nullptr) {
206 clearFlags(fromGroup, from, count, group: fromGroup, flags, removals); }
207 void clearFlags(const iterator &from, int count, uint flags, QVector<Remove> *removals = nullptr) {
208 clearFlags(from, count, group: from.group, flags, removals); }
209
210 bool verifyMoveTo(Group fromGroup, int from, Group toGroup, int to, int count, Group group) const;
211
212 void move(
213 Group fromGroup,
214 int from,
215 Group toGroup,
216 int to,
217 int count,
218 Group group,
219 QVector<Remove> *removals = nullptr,
220 QVector<Insert> *inserts = nullptr);
221 void clear();
222
223 void listItemsInserted(void *list, int index, int count, QVector<Insert> *inserts);
224 void listItemsRemoved(void *list, int index, int count, QVector<Remove> *removals);
225 void listItemsMoved(void *list, int from, int to, int count, QVector<Remove> *removals, QVector<Insert> *inserts);
226 void listItemsChanged(void *list, int index, int count, QVector<Change> *changes);
227
228 void transition(
229 Group from,
230 Group to,
231 QVector<QQmlChangeSet::Change> *removes,
232 QVector<QQmlChangeSet::Change> *inserts);
233
234private:
235 Range m_ranges;
236 iterator m_end;
237 iterator m_cacheIt;
238 int m_groupCount;
239 int m_defaultFlags;
240 int m_removeFlags;
241 int m_moveId;
242
243 inline Range *insert(Range *before, void *list, int index, int count, uint flags);
244 inline Range *erase(Range *range);
245
246 struct MovedFlags
247 {
248 MovedFlags() {}
249 MovedFlags(int moveId, uint flags) : moveId(moveId), flags(flags) {}
250
251 int moveId;
252 uint flags;
253 };
254
255 void listItemsRemoved(
256 QVector<Remove> *translatedRemovals,
257 void *list,
258 QVector<QQmlChangeSet::Change> *removals,
259 QVector<QQmlChangeSet::Change> *insertions = nullptr,
260 QVector<MovedFlags> *movedFlags = nullptr);
261 void listItemsInserted(
262 QVector<Insert> *translatedInsertions,
263 void *list,
264 const QVector<QQmlChangeSet::Change> &insertions,
265 const QVector<MovedFlags> *movedFlags = nullptr);
266 void listItemsChanged(
267 QVector<Change> *translatedChanges,
268 void *list,
269 const QVector<QQmlChangeSet::Change> &changes);
270
271 friend Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list);
272};
273
274Q_DECLARE_TYPEINFO(QQmlListCompositor::Change, Q_PRIMITIVE_TYPE);
275Q_DECLARE_TYPEINFO(QQmlListCompositor::Remove, Q_PRIMITIVE_TYPE);
276Q_DECLARE_TYPEINFO(QQmlListCompositor::Insert, Q_PRIMITIVE_TYPE);
277
278QT_WARNING_PUSH
279// GCC isn't wrong, as groupCount is public in iterator, but we tried Q_ASSUME(),
280// right in front of the loops, and it didn't help, so we disable the warning:
281QT_WARNING_DISABLE_GCC("-Warray-bounds")
282inline QQmlListCompositor::iterator::iterator(
283 Range *range, int offset, Group group, int groupCount)
284 : range(range)
285 , offset(offset)
286 , group(group)
287 , groupFlag(1 << group)
288 , groupCount(groupCount)
289{
290 for (int i = 0; i < groupCount; ++i)
291 index[i] = 0;
292}
293
294inline void QQmlListCompositor::iterator::incrementIndexes(int difference, uint flags)
295{
296 for (int i = 0; i < groupCount; ++i) {
297 if (flags & (1 << i))
298 index[i] += difference;
299 }
300}
301
302inline void QQmlListCompositor::iterator::decrementIndexes(int difference, uint flags)
303{
304 for (int i = 0; i < groupCount; ++i) {
305 if (flags & (1 << i))
306 index[i] -= difference;
307 }
308}
309QT_WARNING_POP // -Warray-bounds
310
311inline QQmlListCompositor::insert_iterator::insert_iterator(
312 Range *range, int offset, Group group, int groupCount)
313 : iterator(range, offset, group, groupCount) {}
314
315inline QQmlListCompositor::Change::Change(const iterator &it, int count, uint flags, int moveId)
316 : count(count), flags(flags), moveId(moveId)
317{
318 for (int i = 0; i < MaximumGroupCount; ++i)
319 index[i] = it.index[i];
320}
321
322Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Group &group);
323Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Range &range);
324Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::iterator &it);
325Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Change &change);
326Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Remove &remove);
327Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Insert &insert);
328Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list);
329
330QT_END_NAMESPACE
331
332#endif
333

source code of qtdeclarative/src/qmlmodels/qqmllistcompositor_p.h