]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemset.cpp
Check if the item supports sequencing before looking for sequence pixmaps
[dolphin.git] / src / kitemviews / kitemset.cpp
1 /*
2 * SPDX-FileCopyrightText: 2013 Frank Reininghaus <frank78ac@googlemail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "kitemset.h"
8
9 KItemSet::iterator KItemSet::insert(int i)
10 {
11 if (m_itemRanges.empty()) {
12 m_itemRanges.push_back(KItemRange(i, 1));
13 return iterator(m_itemRanges.begin(), 0);
14 }
15
16 KItemRangeList::iterator rangeBegin = m_itemRanges.begin();
17 if (i < rangeBegin->index) {
18 // The inserted index is smaller than all existing items.
19 if (i == rangeBegin->index - 1) {
20 // Move the beginning of the first range one item to the front.
21 --rangeBegin->index;
22 ++rangeBegin->count;
23 } else {
24 // Insert a new range at the beginning.
25 rangeBegin = m_itemRanges.insert(rangeBegin, KItemRange(i, 1));
26 }
27
28 return iterator(rangeBegin, 0);
29 }
30
31 KItemRangeList::iterator rangeEnd = m_itemRanges.end();
32 KItemRangeList::iterator lastRange = rangeEnd - 1;
33 if (i >= lastRange->index) {
34 // i either belongs to the last range, or it is larger than all existing items.
35 const int lastItemPlus1 = lastRange->index + lastRange->count;
36 if (i == lastItemPlus1) {
37 // Move the end of the last range one item to the back.
38 ++lastRange->count;
39 } else if (i > lastItemPlus1) {
40 // Append a new range.
41 lastRange = m_itemRanges.insert(rangeEnd, KItemRange(i, 1));
42 }
43
44 return iterator(lastRange, i - lastRange->index);
45 }
46
47 // We know that i is between the smallest existing item and the first item
48 // of the last range. Find the lowest range whose 'index' is smaller than i.
49 KItemRangeList::iterator low = rangeBegin;
50 KItemRangeList::iterator high = lastRange;
51
52 while (low + 1 != high) {
53 const int span = high - low;
54 Q_ASSERT(span >= 2);
55
56 KItemRangeList::iterator mid = low + span / 2;
57 if (mid->index > i) {
58 high = mid;
59 } else {
60 low = mid;
61 }
62 }
63
64 Q_ASSERT(low->index <= i && high->index > i);
65
66 if (i == low->index + low->count) {
67 // i is just one item behind the range low.
68 if (i == high->index - 1) {
69 // i closes the gap between low and high. Merge the two ranges.
70 const int newRangeCount = low->count + 1 + high->count;
71 KItemRangeList::iterator behindNewRange = m_itemRanges.erase(high);
72 KItemRangeList::iterator newRange = behindNewRange - 1;
73 newRange->count = newRangeCount;
74 return iterator(newRange, i - newRange->index);
75 } else {
76 // Extend low by one item.
77 ++low->count;
78 return iterator(low, low->count - 1);
79 }
80 } else if (i > low->index + low->count) {
81 if (i == high->index - 1) {
82 // Extend high by one item to the front.
83 --high->index;
84 ++high->count;
85 return iterator(high, 0);
86 } else {
87 // Insert a new range between low and high.
88 KItemRangeList::iterator newRange = m_itemRanges.insert(high, KItemRange(i, 1));
89 return iterator(newRange, 0);
90 }
91 } else {
92 // The range low already contains i.
93 return iterator(low, i - low->index);
94 }
95 }
96
97 KItemSet::iterator KItemSet::erase(iterator it)
98 {
99 KItemRangeList::iterator rangeIt = it.m_rangeIt;
100
101 if (it.m_offset == 0) {
102 // Removed index is at the beginning of a range.
103 if (rangeIt->count > 1) {
104 ++rangeIt->index;
105 --rangeIt->count;
106 } else {
107 // The range only contains the removed index.
108 rangeIt = m_itemRanges.erase(rangeIt);
109 }
110 return iterator(rangeIt, 0);
111 } else if (it.m_offset == rangeIt->count - 1) {
112 // Removed index is at the end of a range.
113 --rangeIt->count;
114 ++rangeIt;
115 return iterator(rangeIt, 0);
116 } else {
117 // The removed index is in the middle of a range.
118 const int newRangeIndex = *it + 1;
119 const int newRangeCount = rangeIt->count - it.m_offset - 1;
120 const KItemRange newRange(newRangeIndex, newRangeCount);
121
122 rangeIt->count = it.m_offset;
123 ++rangeIt;
124 rangeIt = m_itemRanges.insert(rangeIt, newRange);
125
126 return iterator(rangeIt, 0);
127 }
128 }
129
130 KItemSet KItemSet::operator+(const KItemSet &other) const
131 {
132 KItemSet sum;
133
134 KItemRangeList::const_iterator it1 = m_itemRanges.constBegin();
135 KItemRangeList::const_iterator it2 = other.m_itemRanges.constBegin();
136
137 const KItemRangeList::const_iterator end1 = m_itemRanges.constEnd();
138 const KItemRangeList::const_iterator end2 = other.m_itemRanges.constEnd();
139
140 while (it1 != end1 || it2 != end2) {
141 if (it1 == end1) {
142 // We are past the end of 'this' already. Append all remaining
143 // item ranges from 'other'.
144 while (it2 != end2) {
145 sum.m_itemRanges.append(*it2);
146 ++it2;
147 }
148 } else if (it2 == end2) {
149 // We are past the end of 'other' already. Append all remaining
150 // item ranges from 'this'.
151 while (it1 != end1) {
152 sum.m_itemRanges.append(*it1);
153 ++it1;
154 }
155 } else {
156 // Find the beginning of the next range.
157 int index = qMin(it1->index, it2->index);
158 int count = 0;
159
160 do {
161 if (it1 != end1 && it1->index <= index + count) {
162 // The next range from 'this' overlaps with the current range in the sum.
163 count = qMax(count, it1->index + it1->count - index);
164 ++it1;
165 }
166
167 if (it2 != end2 && it2->index <= index + count) {
168 // The next range from 'other' overlaps with the current range in the sum.
169 count = qMax(count, it2->index + it2->count - index);
170 ++it2;
171 }
172 } while ((it1 != end1 && it1->index <= index + count) || (it2 != end2 && it2->index <= index + count));
173
174 sum.m_itemRanges.append(KItemRange(index, count));
175 }
176 }
177
178 return sum;
179 }
180
181 KItemSet KItemSet::operator^(const KItemSet &other) const
182 {
183 // We are looking for all ints which are either in *this or in other,
184 // but not in both.
185 KItemSet result;
186
187 // When we go through all integers from INT_MIN to INT_MAX and start
188 // in the state "do not add to result", every beginning/end of a range
189 // of *this and other toggles the "add/do not add to result" state.
190 // Therefore, we just have to put ints where any range starts/ends to
191 // a sorted array, and then we can calculate the result quite easily.
192 QVector<int> rangeBoundaries;
193 rangeBoundaries.resize(2 * (m_itemRanges.count() + other.m_itemRanges.count()));
194 const QVector<int>::iterator begin = rangeBoundaries.begin();
195 const QVector<int>::iterator end = rangeBoundaries.end();
196 QVector<int>::iterator it = begin;
197
198 for (const KItemRange &range : std::as_const(m_itemRanges)) {
199 *it++ = range.index;
200 *it++ = range.index + range.count;
201 }
202
203 const QVector<int>::iterator middle = it;
204
205 for (const KItemRange &range : std::as_const(other.m_itemRanges)) {
206 *it++ = range.index;
207 *it++ = range.index + range.count;
208 }
209 Q_ASSERT(it == end);
210
211 std::inplace_merge(begin, middle, end);
212
213 it = begin;
214 while (it != end) {
215 const int rangeBegin = *it;
216 ++it;
217
218 if (*it == rangeBegin) {
219 // It seems that ranges from both *this and other start at
220 // rangeBegin. Do not start a new range, but read the next int.
221 //
222 // Example: Consider the symmetric difference of the sets
223 // {1, 2, 3, 4} and {1, 2}. The sorted list of range boundaries is
224 // 1 1 3 5. Discarding the duplicate 1 yields the result
225 // rangeBegin = 3, rangeEnd = 5, which corresponds to the set {3, 4}.
226 ++it;
227 } else {
228 // The end of the current range is the next *single* int that we
229 // find. If an int appears twice in rangeBoundaries, the range does
230 // not end.
231 //
232 // Example: Consider the symmetric difference of the sets
233 // {1, 2, 3, 4, 8, 9, 10} and {5, 6, 7}. The sorted list of range
234 // boundaries is 1 5 5 8 8 11, and discarding all duplicates yields
235 // the result rangeBegin = 1, rangeEnd = 11, which corresponds to
236 // the set {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}.
237 bool foundEndOfRange = false;
238 int rangeEnd;
239 do {
240 rangeEnd = *it;
241 ++it;
242
243 if (it == end || *it != rangeEnd) {
244 foundEndOfRange = true;
245 } else {
246 ++it;
247 }
248 } while (!foundEndOfRange);
249
250 result.m_itemRanges.append(KItemRange(rangeBegin, rangeEnd - rangeBegin));
251 }
252 }
253
254 return result;
255 }
256
257 bool KItemSet::isValid() const
258 {
259 const KItemRangeList::const_iterator begin = m_itemRanges.constBegin();
260 const KItemRangeList::const_iterator end = m_itemRanges.constEnd();
261
262 for (KItemRangeList::const_iterator it = begin; it != end; ++it) {
263 if (it->count <= 0) {
264 return false;
265 }
266
267 if (it != begin) {
268 const KItemRangeList::const_iterator previous = it - 1;
269 if (previous->index + previous->count >= it->index) {
270 return false;
271 }
272 }
273 }
274
275 return true;
276 }
277
278 KItemRangeList::iterator KItemSet::rangeForItem(int i)
279 {
280 const KItemRangeList::iterator end = m_itemRanges.end();
281 KItemRangeList::iterator low = m_itemRanges.begin();
282 KItemRangeList::iterator high = end;
283
284 if (low == end || low->index > i) {
285 return end;
286 }
287
288 while (low != high && low + 1 != high) {
289 KItemRangeList::iterator mid = low + (high - low) / 2;
290 if (mid->index > i) {
291 high = mid;
292 } else {
293 low = mid;
294 }
295 }
296
297 Q_ASSERT(low->index <= i);
298 if (low->index + low->count > i) {
299 return low;
300 }
301
302 return end;
303 }
304
305 KItemRangeList::const_iterator KItemSet::constRangeForItem(int i) const
306 {
307 const KItemRangeList::const_iterator end = m_itemRanges.constEnd();
308 KItemRangeList::const_iterator low = m_itemRanges.constBegin();
309 KItemRangeList::const_iterator high = end;
310
311 if (low == end || low->index > i) {
312 return end;
313 }
314
315 while (low != high && low + 1 != high) {
316 KItemRangeList::const_iterator mid = low + (high - low) / 2;
317 if (mid->index > i) {
318 high = mid;
319 } else {
320 low = mid;
321 }
322 }
323
324 Q_ASSERT(low->index <= i);
325 if (low->index + low->count > i) {
326 return low;
327 }
328
329 return end;
330 }