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 }