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