]>
cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemset.cpp
1 /***************************************************************************
2 * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
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. *
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. *
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 ***************************************************************************/
23 KItemSet::iterator
KItemSet::insert(int i
)
25 if (m_itemRanges
.empty()) {
26 m_itemRanges
.push_back(KItemRange(i
, 1));
27 return iterator(m_itemRanges
.begin(), 0);
30 KItemRangeList::iterator rangeBegin
= m_itemRanges
.begin();
31 if (i
< rangeBegin
->index
) {
32 // The inserted index is smaller than all existing items.
33 if (i
== rangeBegin
->index
- 1) {
34 // Move the beginning of the first range one item to the front.
38 // Insert a new range at the beginning.
39 rangeBegin
= m_itemRanges
.insert(rangeBegin
, KItemRange(i
, 1));
42 return iterator(rangeBegin
, 0);
45 KItemRangeList::iterator rangeEnd
= m_itemRanges
.end();
46 KItemRangeList::iterator lastRange
= rangeEnd
- 1;
47 if (i
>= lastRange
->index
) {
48 // i either belongs to the last range, or it is larger than all existing items.
49 const int lastItemPlus1
= lastRange
->index
+ lastRange
->count
;
50 if (i
== lastItemPlus1
) {
51 // Move the end of the last range one item to the back.
53 } else if (i
> lastItemPlus1
) {
54 // Append a new range.
55 lastRange
= m_itemRanges
.insert(rangeEnd
, KItemRange(i
, 1));
58 return iterator(lastRange
, i
- lastRange
->index
);
61 // We know that i is between the smallest existing item and the first item
62 // of the last range. Find the lowest range whose 'index' is smaller than i.
63 KItemRangeList::iterator low
= rangeBegin
;
64 KItemRangeList::iterator high
= lastRange
;
66 while (low
+ 1 != high
) {
67 const int span
= high
- low
;
70 KItemRangeList::iterator mid
= low
+ span
/ 2;
78 Q_ASSERT(low
->index
<= i
&& high
->index
> i
);
80 if (i
== low
->index
+ low
->count
) {
81 // i is just one item behind the range low.
82 if (i
== high
->index
- 1) {
83 // i closes the gap between low and high. Merge the two ranges.
84 const int newRangeCount
= low
->count
+ 1 + high
->count
;
85 KItemRangeList::iterator behindNewRange
= m_itemRanges
.erase(high
);
86 KItemRangeList::iterator newRange
= behindNewRange
- 1;
87 newRange
->count
= newRangeCount
;
88 return iterator(newRange
, i
- newRange
->index
);
90 // Extend low by one item.
92 return iterator(low
, low
->count
- 1);
94 } else if (i
> low
->index
+ low
->count
) {
95 if (i
== high
->index
- 1) {
96 // Extend high by one item to the front.
99 return iterator(high
, 0);
101 // Insert a new range between low and high.
102 KItemRangeList::iterator newRange
= m_itemRanges
.insert(high
, KItemRange(i
, 1));
103 return iterator(newRange
, 0);
106 // The range low already contains i.
107 return iterator(low
, i
- low
->index
);
111 KItemSet::iterator
KItemSet::erase(iterator it
)
113 KItemRangeList::iterator rangeIt
= it
.m_rangeIt
;
115 if (it
.m_offset
== 0) {
116 // Removed index is at the beginning of a range.
117 if (rangeIt
->count
> 1) {
121 // The range only contains the removed index.
122 rangeIt
= m_itemRanges
.erase(rangeIt
);
124 return iterator(rangeIt
, 0);
125 } else if (it
.m_offset
== rangeIt
->count
- 1) {
126 // Removed index is at the end of a range.
129 return iterator(rangeIt
, 0);
131 // The removed index is in the middle of a range.
132 const int newRangeIndex
= *it
+ 1;
133 const int newRangeCount
= rangeIt
->count
- it
.m_offset
- 1;
134 const KItemRange
newRange(newRangeIndex
, newRangeCount
);
136 rangeIt
->count
= it
.m_offset
;
138 rangeIt
= m_itemRanges
.insert(rangeIt
, newRange
);
140 return iterator(rangeIt
, 0);
144 KItemSet
KItemSet::operator+(const KItemSet
& other
) const
148 KItemRangeList::const_iterator it1
= m_itemRanges
.constBegin();
149 KItemRangeList::const_iterator it2
= other
.m_itemRanges
.constBegin();
151 const KItemRangeList::const_iterator end1
= m_itemRanges
.constEnd();
152 const KItemRangeList::const_iterator end2
= other
.m_itemRanges
.constEnd();
154 while (it1
!= end1
|| it2
!= end2
) {
156 // We are past the end of 'this' already. Append all remaining
157 // item ranges from 'other'.
158 while (it2
!= end2
) {
159 sum
.m_itemRanges
.append(*it2
);
162 } else if (it2
== end2
) {
163 // We are past the end of 'other' already. Append all remaining
164 // item ranges from 'this'.
165 while (it1
!= end1
) {
166 sum
.m_itemRanges
.append(*it1
);
170 // Find the beginning of the next range.
171 int index
= qMin(it1
->index
, it2
->index
);
175 if (it1
!= end1
&& it1
->index
<= index
+ count
) {
176 // The next range from 'this' overlaps with the current range in the sum.
177 count
= qMax(count
, it1
->index
+ it1
->count
- index
);
181 if (it2
!= end2
&& it2
->index
<= index
+ count
) {
182 // The next range from 'other' overlaps with the current range in the sum.
183 count
= qMax(count
, it2
->index
+ it2
->count
- index
);
186 } while ((it1
!= end1
&& it1
->index
<= index
+ count
)
187 || (it2
!= end2
&& it2
->index
<= index
+ count
));
189 sum
.m_itemRanges
.append(KItemRange(index
, count
));
196 KItemSet
KItemSet::operator^(const KItemSet
& other
) const
198 // We are looking for all ints which are either in *this or in other,
202 // When we go through all integers from INT_MIN to INT_MAX and start
203 // in the state "do not add to result", every beginning/end of a range
204 // of *this and other toggles the "add/do not add to result" state.
205 // Therefore, we just have to put ints where any range starts/ends to
206 // a sorted array, and then we can calculate the result quite easily.
207 QVector
<int> rangeBoundaries
;
208 rangeBoundaries
.resize(2 * (m_itemRanges
.count() + other
.m_itemRanges
.count()));
209 const QVector
<int>::iterator begin
= rangeBoundaries
.begin();
210 const QVector
<int>::iterator end
= rangeBoundaries
.end();
211 QVector
<int>::iterator it
= begin
;
213 foreach (const KItemRange
& range
, m_itemRanges
) {
215 *it
++ = range
.index
+ range
.count
;
218 const QVector
<int>::iterator middle
= it
;
220 foreach (const KItemRange
& range
, other
.m_itemRanges
) {
222 *it
++ = range
.index
+ range
.count
;
226 std::inplace_merge(begin
, middle
, end
);
230 const int rangeBegin
= *it
;
233 if (*it
== rangeBegin
) {
234 // It seems that ranges from both *this and other start at
235 // rangeBegin. Do not start a new range, but read the next int.
237 // Example: Consider the symmetric difference of the sets
238 // {1, 2, 3, 4} and {1, 2}. The sorted list of range boundaries is
239 // 1 1 3 5. Discarding the duplicate 1 yields the result
240 // rangeBegin = 3, rangeEnd = 5, which corresponds to the set {3, 4}.
243 // The end of the current range is the next *single* int that we
244 // find. If an int appears twice in rangeBoundaries, the range does
247 // Example: Consider the symmetric difference of the sets
248 // {1, 2, 3, 4, 8, 9, 10} and {5, 6, 7}. The sorted list of range
249 // boundaries is 1 5 5 8 8 11, and discarding all duplicates yields
250 // the result rangeBegin = 1, rangeEnd = 11, which corresponds to
251 // the set {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}.
252 bool foundEndOfRange
= false;
258 if (it
== end
|| *it
!= rangeEnd
) {
259 foundEndOfRange
= true;
263 } while (!foundEndOfRange
);
265 result
.m_itemRanges
.append(KItemRange(rangeBegin
, rangeEnd
- rangeBegin
));
272 bool KItemSet::isValid() const
274 const KItemRangeList::const_iterator begin
= m_itemRanges
.constBegin();
275 const KItemRangeList::const_iterator end
= m_itemRanges
.constEnd();
277 for (KItemRangeList::const_iterator it
= begin
; it
!= end
; ++it
) {
278 if (it
->count
<= 0) {
283 const KItemRangeList::const_iterator previous
= it
- 1;
284 if (previous
->index
+ previous
->count
>= it
->index
) {
293 KItemRangeList::iterator
KItemSet::rangeForItem(int i
)
295 const KItemRangeList::iterator end
= m_itemRanges
.end();
296 KItemRangeList::iterator low
= m_itemRanges
.begin();
297 KItemRangeList::iterator high
= end
;
299 if (low
== end
|| low
->index
> i
) {
303 while (low
!= high
&& low
+ 1 != high
) {
304 KItemRangeList::iterator mid
= low
+ (high
- low
) / 2;
305 if (mid
->index
> i
) {
312 Q_ASSERT(low
->index
<= i
);
313 if (low
->index
+ low
->count
> i
) {
320 KItemRangeList::const_iterator
KItemSet::constRangeForItem(int i
) const
322 const KItemRangeList::const_iterator end
= m_itemRanges
.constEnd();
323 KItemRangeList::const_iterator low
= m_itemRanges
.constBegin();
324 KItemRangeList::const_iterator high
= end
;
326 if (low
== end
|| low
->index
> i
) {
330 while (low
!= high
&& low
+ 1 != high
) {
331 KItemRangeList::const_iterator mid
= low
+ (high
- low
) / 2;
332 if (mid
->index
> i
) {
339 Q_ASSERT(low
->index
<= i
);
340 if (low
->index
+ low
->count
> i
) {