File indexing completed on 2024-04-28 05:45:10
0001 /* 0002 * SPDX-FileCopyrightText: 2013 Frank Reininghaus <frank78ac@googlemail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kitemset.h" 0008 0009 KItemSet::iterator KItemSet::insert(int i) 0010 { 0011 if (m_itemRanges.empty()) { 0012 m_itemRanges.push_back(KItemRange(i, 1)); 0013 return iterator(m_itemRanges.begin(), 0); 0014 } 0015 0016 KItemRangeList::iterator rangeBegin = m_itemRanges.begin(); 0017 if (i < rangeBegin->index) { 0018 // The inserted index is smaller than all existing items. 0019 if (i == rangeBegin->index - 1) { 0020 // Move the beginning of the first range one item to the front. 0021 --rangeBegin->index; 0022 ++rangeBegin->count; 0023 } else { 0024 // Insert a new range at the beginning. 0025 rangeBegin = m_itemRanges.insert(rangeBegin, KItemRange(i, 1)); 0026 } 0027 0028 return iterator(rangeBegin, 0); 0029 } 0030 0031 KItemRangeList::iterator rangeEnd = m_itemRanges.end(); 0032 KItemRangeList::iterator lastRange = rangeEnd - 1; 0033 if (i >= lastRange->index) { 0034 // i either belongs to the last range, or it is larger than all existing items. 0035 const int lastItemPlus1 = lastRange->index + lastRange->count; 0036 if (i == lastItemPlus1) { 0037 // Move the end of the last range one item to the back. 0038 ++lastRange->count; 0039 } else if (i > lastItemPlus1) { 0040 // Append a new range. 0041 lastRange = m_itemRanges.insert(rangeEnd, KItemRange(i, 1)); 0042 } 0043 0044 return iterator(lastRange, i - lastRange->index); 0045 } 0046 0047 // We know that i is between the smallest existing item and the first item 0048 // of the last range. Find the lowest range whose 'index' is smaller than i. 0049 KItemRangeList::iterator low = rangeBegin; 0050 KItemRangeList::iterator high = lastRange; 0051 0052 while (low + 1 != high) { 0053 const int span = high - low; 0054 Q_ASSERT(span >= 2); 0055 0056 KItemRangeList::iterator mid = low + span / 2; 0057 if (mid->index > i) { 0058 high = mid; 0059 } else { 0060 low = mid; 0061 } 0062 } 0063 0064 Q_ASSERT(low->index <= i && high->index > i); 0065 0066 if (i == low->index + low->count) { 0067 // i is just one item behind the range low. 0068 if (i == high->index - 1) { 0069 // i closes the gap between low and high. Merge the two ranges. 0070 const int newRangeCount = low->count + 1 + high->count; 0071 KItemRangeList::iterator behindNewRange = m_itemRanges.erase(high); 0072 KItemRangeList::iterator newRange = behindNewRange - 1; 0073 newRange->count = newRangeCount; 0074 return iterator(newRange, i - newRange->index); 0075 } else { 0076 // Extend low by one item. 0077 ++low->count; 0078 return iterator(low, low->count - 1); 0079 } 0080 } else if (i > low->index + low->count) { 0081 if (i == high->index - 1) { 0082 // Extend high by one item to the front. 0083 --high->index; 0084 ++high->count; 0085 return iterator(high, 0); 0086 } else { 0087 // Insert a new range between low and high. 0088 KItemRangeList::iterator newRange = m_itemRanges.insert(high, KItemRange(i, 1)); 0089 return iterator(newRange, 0); 0090 } 0091 } else { 0092 // The range low already contains i. 0093 return iterator(low, i - low->index); 0094 } 0095 } 0096 0097 KItemSet::iterator KItemSet::erase(iterator it) 0098 { 0099 KItemRangeList::iterator rangeIt = it.m_rangeIt; 0100 0101 if (it.m_offset == 0) { 0102 // Removed index is at the beginning of a range. 0103 if (rangeIt->count > 1) { 0104 ++rangeIt->index; 0105 --rangeIt->count; 0106 } else { 0107 // The range only contains the removed index. 0108 rangeIt = m_itemRanges.erase(rangeIt); 0109 } 0110 return iterator(rangeIt, 0); 0111 } else if (it.m_offset == rangeIt->count - 1) { 0112 // Removed index is at the end of a range. 0113 --rangeIt->count; 0114 ++rangeIt; 0115 return iterator(rangeIt, 0); 0116 } else { 0117 // The removed index is in the middle of a range. 0118 const int newRangeIndex = *it + 1; 0119 const int newRangeCount = rangeIt->count - it.m_offset - 1; 0120 const KItemRange newRange(newRangeIndex, newRangeCount); 0121 0122 rangeIt->count = it.m_offset; 0123 ++rangeIt; 0124 rangeIt = m_itemRanges.insert(rangeIt, newRange); 0125 0126 return iterator(rangeIt, 0); 0127 } 0128 } 0129 0130 KItemSet KItemSet::operator+(const KItemSet &other) const 0131 { 0132 KItemSet sum; 0133 0134 KItemRangeList::const_iterator it1 = m_itemRanges.constBegin(); 0135 KItemRangeList::const_iterator it2 = other.m_itemRanges.constBegin(); 0136 0137 const KItemRangeList::const_iterator end1 = m_itemRanges.constEnd(); 0138 const KItemRangeList::const_iterator end2 = other.m_itemRanges.constEnd(); 0139 0140 while (it1 != end1 || it2 != end2) { 0141 if (it1 == end1) { 0142 // We are past the end of 'this' already. Append all remaining 0143 // item ranges from 'other'. 0144 while (it2 != end2) { 0145 sum.m_itemRanges.append(*it2); 0146 ++it2; 0147 } 0148 } else if (it2 == end2) { 0149 // We are past the end of 'other' already. Append all remaining 0150 // item ranges from 'this'. 0151 while (it1 != end1) { 0152 sum.m_itemRanges.append(*it1); 0153 ++it1; 0154 } 0155 } else { 0156 // Find the beginning of the next range. 0157 int index = qMin(it1->index, it2->index); 0158 int count = 0; 0159 0160 do { 0161 if (it1 != end1 && it1->index <= index + count) { 0162 // The next range from 'this' overlaps with the current range in the sum. 0163 count = qMax(count, it1->index + it1->count - index); 0164 ++it1; 0165 } 0166 0167 if (it2 != end2 && it2->index <= index + count) { 0168 // The next range from 'other' overlaps with the current range in the sum. 0169 count = qMax(count, it2->index + it2->count - index); 0170 ++it2; 0171 } 0172 } while ((it1 != end1 && it1->index <= index + count) || (it2 != end2 && it2->index <= index + count)); 0173 0174 sum.m_itemRanges.append(KItemRange(index, count)); 0175 } 0176 } 0177 0178 return sum; 0179 } 0180 0181 KItemSet KItemSet::operator^(const KItemSet &other) const 0182 { 0183 // We are looking for all ints which are either in *this or in other, 0184 // but not in both. 0185 KItemSet result; 0186 0187 // When we go through all integers from INT_MIN to INT_MAX and start 0188 // in the state "do not add to result", every beginning/end of a range 0189 // of *this and other toggles the "add/do not add to result" state. 0190 // Therefore, we just have to put ints where any range starts/ends to 0191 // a sorted array, and then we can calculate the result quite easily. 0192 QVector<int> rangeBoundaries; 0193 rangeBoundaries.resize(2 * (m_itemRanges.count() + other.m_itemRanges.count())); 0194 const QVector<int>::iterator begin = rangeBoundaries.begin(); 0195 const QVector<int>::iterator end = rangeBoundaries.end(); 0196 QVector<int>::iterator it = begin; 0197 0198 for (const KItemRange &range : std::as_const(m_itemRanges)) { 0199 *it++ = range.index; 0200 *it++ = range.index + range.count; 0201 } 0202 0203 const QVector<int>::iterator middle = it; 0204 0205 for (const KItemRange &range : std::as_const(other.m_itemRanges)) { 0206 *it++ = range.index; 0207 *it++ = range.index + range.count; 0208 } 0209 Q_ASSERT(it == end); 0210 0211 std::inplace_merge(begin, middle, end); 0212 0213 it = begin; 0214 while (it != end) { 0215 const int rangeBegin = *it; 0216 ++it; 0217 0218 if (*it == rangeBegin) { 0219 // It seems that ranges from both *this and other start at 0220 // rangeBegin. Do not start a new range, but read the next int. 0221 // 0222 // Example: Consider the symmetric difference of the sets 0223 // {1, 2, 3, 4} and {1, 2}. The sorted list of range boundaries is 0224 // 1 1 3 5. Discarding the duplicate 1 yields the result 0225 // rangeBegin = 3, rangeEnd = 5, which corresponds to the set {3, 4}. 0226 ++it; 0227 } else { 0228 // The end of the current range is the next *single* int that we 0229 // find. If an int appears twice in rangeBoundaries, the range does 0230 // not end. 0231 // 0232 // Example: Consider the symmetric difference of the sets 0233 // {1, 2, 3, 4, 8, 9, 10} and {5, 6, 7}. The sorted list of range 0234 // boundaries is 1 5 5 8 8 11, and discarding all duplicates yields 0235 // the result rangeBegin = 1, rangeEnd = 11, which corresponds to 0236 // the set {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}. 0237 bool foundEndOfRange = false; 0238 int rangeEnd; 0239 do { 0240 rangeEnd = *it; 0241 ++it; 0242 0243 if (it == end || *it != rangeEnd) { 0244 foundEndOfRange = true; 0245 } else { 0246 ++it; 0247 } 0248 } while (!foundEndOfRange); 0249 0250 result.m_itemRanges.append(KItemRange(rangeBegin, rangeEnd - rangeBegin)); 0251 } 0252 } 0253 0254 return result; 0255 } 0256 0257 bool KItemSet::isValid() const 0258 { 0259 const KItemRangeList::const_iterator begin = m_itemRanges.constBegin(); 0260 const KItemRangeList::const_iterator end = m_itemRanges.constEnd(); 0261 0262 for (KItemRangeList::const_iterator it = begin; it != end; ++it) { 0263 if (it->count <= 0) { 0264 return false; 0265 } 0266 0267 if (it != begin) { 0268 const KItemRangeList::const_iterator previous = it - 1; 0269 if (previous->index + previous->count >= it->index) { 0270 return false; 0271 } 0272 } 0273 } 0274 0275 return true; 0276 } 0277 0278 KItemRangeList::iterator KItemSet::rangeForItem(int i) 0279 { 0280 const KItemRangeList::iterator end = m_itemRanges.end(); 0281 KItemRangeList::iterator low = m_itemRanges.begin(); 0282 KItemRangeList::iterator high = end; 0283 0284 if (low == end || low->index > i) { 0285 return end; 0286 } 0287 0288 while (low != high && low + 1 != high) { 0289 KItemRangeList::iterator mid = low + (high - low) / 2; 0290 if (mid->index > i) { 0291 high = mid; 0292 } else { 0293 low = mid; 0294 } 0295 } 0296 0297 Q_ASSERT(low->index <= i); 0298 if (low->index + low->count > i) { 0299 return low; 0300 } 0301 0302 return end; 0303 } 0304 0305 KItemRangeList::const_iterator KItemSet::constRangeForItem(int i) const 0306 { 0307 const KItemRangeList::const_iterator end = m_itemRanges.constEnd(); 0308 KItemRangeList::const_iterator low = m_itemRanges.constBegin(); 0309 KItemRangeList::const_iterator high = end; 0310 0311 if (low == end || low->index > i) { 0312 return end; 0313 } 0314 0315 while (low != high && low + 1 != high) { 0316 KItemRangeList::const_iterator mid = low + (high - low) / 2; 0317 if (mid->index > i) { 0318 high = mid; 0319 } else { 0320 low = mid; 0321 } 0322 } 0323 0324 Q_ASSERT(low->index <= i); 0325 if (low->index + low->count > i) { 0326 return low; 0327 } 0328 0329 return end; 0330 }