File indexing completed on 2024-05-05 04:38:43

0001 /*
0002     SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #ifndef KDEVPLATFORM_CONVENIENTFREELIST_H
0008 #define KDEVPLATFORM_CONVENIENTFREELIST_H
0009 
0010 #include <QPair>
0011 #include <QVector>
0012 
0013 #include "embeddedfreetree.h"
0014 #include "kdevvarlengtharray.h"
0015 
0016 namespace KDevelop {
0017 
0018 template<class Data, class Handler>
0019 class ConvenientEmbeddedSetIterator;
0020 template<class Data, class Handler, class Data2, class Handler2, class KeyExtractor>
0021 class ConvenientEmbeddedSetFilterIterator;
0022 
0023 ///A convenience-class for accessing the data in a set managed by the EmbeddedFreeTree algorithms.
0024 template<class Data, class Handler>
0025 class ConstantConvenientEmbeddedSet
0026 {
0027 public:
0028     ConstantConvenientEmbeddedSet() : m_data(nullptr)
0029     {
0030     }
0031     ConstantConvenientEmbeddedSet(const Data* data, uint count, int centralFreeItem) : m_data(data)
0032         , m_dataSize(count)
0033         , m_centralFreeItem(centralFreeItem)
0034     {
0035     }
0036 
0037     ///Returns whether the item is contained in this set
0038     bool contains(const Data& data) const
0039     {
0040         return indexOf(data) != -1;
0041     }
0042 
0043     ///Returns the position of the item in the underlying array, or -1 if it is not contained
0044     int indexOf(const Data& data) const
0045     {
0046         EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
0047         return alg.indexOf(data);
0048     }
0049 
0050     ///Returns the size of the underlying array
0051     uint dataSize() const
0052     {
0053         return m_dataSize;
0054     }
0055 
0056     uint countFreeItems()
0057     {
0058         EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
0059         return alg.countFreeItems();
0060     }
0061 
0062     void verify()
0063     {
0064         EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
0065         alg.verifyTreeConsistent();
0066         alg.verifyOrder();
0067     }
0068 
0069     ///Returns the underlying array. That array may contain invalid/free items.
0070     const Data* data() const
0071     {
0072         return m_data;
0073     }
0074 
0075     ///Returns the first valid index that has a data-value larger or equal to @p data.
0076     ///Returns -1 if nothing is found.
0077     int lowerBound(const Data& data) const
0078     {
0079         EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
0080         return alg.lowerBound(data, 0, m_dataSize);
0081     }
0082 
0083     ///Returns the first valid index that has a data-value larger or equal to @p data,
0084     ///and that is in the range [start, end).
0085     ///Returns -1 if nothing is found.
0086     int lowerBound(const Data& data, uint start, uint end) const
0087     {
0088         EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
0089         return alg.lowerBound(data, start, end);
0090     }
0091 
0092     ///Finds a valid most central in the range [start, end).
0093     ///Returns -1 if no such item exists.
0094     int validMiddle(uint start, uint end)
0095     {
0096         if (end <= start)
0097             return -1;
0098 
0099         int firstTry = ((end - start) / 2) + start;
0100 
0101         int thisTry = firstTry;
0102         while (thisTry < ( int )end && Handler::isFree(m_data[thisTry]))
0103             ++thisTry;
0104 
0105         if (thisTry != ( int )end)
0106             return thisTry;
0107 
0108         //Nothing find on right side of middle, try the other direction
0109         thisTry = firstTry - 1;
0110         while (thisTry >= ( int )start && Handler::isFree(m_data[thisTry]))
0111             --thisTry;
0112 
0113         if (thisTry >= ( int )start)
0114             return thisTry;
0115         else
0116             return -1;
0117     }
0118 
0119     ///Returns the first valid item in the range [pos, end), or -1
0120     int firstValidItem(int start, int end = -1) const
0121     {
0122         if (end == -1)
0123             end = ( int )m_dataSize;
0124         for (; start < end; ++start)
0125             if (!Handler::isFree(m_data[start]))
0126                 return start;
0127 
0128         return -1;
0129     }
0130 
0131     ///Returns the last valid item in the range [pos, end), or -1
0132     int lastValidItem(int start = 0, int end = -1) const
0133     {
0134         if (end == -1)
0135             end = ( int )m_dataSize;
0136         --end;
0137         for (; end >= start; --end)
0138             if (!Handler::isFree(m_data[end]))
0139                 return end;
0140 
0141         return -1;
0142     }
0143 
0144     using Iterator = ConvenientEmbeddedSetIterator<Data, Handler>;
0145 
0146     ConvenientEmbeddedSetIterator<Data, Handler> iterator() const;
0147 
0148 //         protected:
0149     const Data* m_data;
0150     uint m_dataSize = 0;
0151     int m_centralFreeItem = -1;
0152 };
0153 
0154 ///Convenient iterator that automatically skips invalid/free items in the array.
0155 template<class Data, class Handler>
0156 class ConvenientEmbeddedSetIterator : public ConstantConvenientEmbeddedSet<Data
0157         , Handler>
0158 {
0159 public:
0160     explicit ConvenientEmbeddedSetIterator(const Data* data = nullptr, uint count = 0,
0161                                            int centralFreeItem = -1) : ConstantConvenientEmbeddedSet<Data, Handler>(
0162             data, count, centralFreeItem)
0163     {
0164         //Move to first valid position
0165         moveToValid();
0166     }
0167 
0168     ///Returns true of this iterator has a value to return
0169     operator bool() const {
0170         return m_pos != this->m_dataSize;
0171     }
0172 
0173     const Data* operator->() const
0174     {
0175         return &this->m_data[m_pos];
0176     }
0177 
0178     const Data& operator*() const
0179     {
0180         return this->m_data[m_pos];
0181     }
0182 
0183     ConvenientEmbeddedSetIterator& operator++()
0184     {
0185         ++m_pos;
0186         moveToValid();
0187         return *this;
0188     }
0189 
0190 protected:
0191     inline void moveToValid()
0192     {
0193         while (this->m_pos < this->m_dataSize && (Handler::isFree(this->m_data[this->m_pos])))
0194             ++this->m_pos;
0195     }
0196     uint m_pos = 0;
0197 };
0198 
0199 ///An iterator that allows efficient matching between two lists with different data type.
0200 ///Important: It must be possible to extract the data-type of the second list from the items in the first list
0201 ///The second list must be sorted by that data.
0202 ///The first list must primarily be sorted by that data, but is allowed to
0203 ///be sub-ordered by something else, and multiple items in the first list are allowed to match one item in the second.
0204 ///This iterator iterates through all items in the first list that have extracted key-data that is in represented in the second.
0205 template<class Data, class Handler, class Data2, class Handler2, class KeyExtractor>
0206 class ConvenientEmbeddedSetFilterIterator : public ConvenientEmbeddedSetIterator<Data
0207         , Handler>
0208 {
0209 public:
0210     ConvenientEmbeddedSetFilterIterator()
0211     {
0212     }
0213     ConvenientEmbeddedSetFilterIterator(const ConvenientEmbeddedSetIterator<Data, Handler>& base,
0214                                         const ConvenientEmbeddedSetIterator<Data2,
0215                                             Handler2>& rhs) : ConvenientEmbeddedSetIterator<Data, Handler>(base)
0216         , m_rhs(rhs)
0217         , m_match(-1)
0218     {
0219         boundStack.append(qMakePair(qMakePair(0u, this->m_dataSize), qMakePair(0u, rhs.m_dataSize)));
0220         go();
0221     }
0222 
0223     operator bool() const {
0224         return m_match != -1;
0225     }
0226 
0227     const Data* operator->() const
0228     {
0229         Q_ASSERT(m_match != -1);
0230         return &this->m_data[m_match];
0231     }
0232 
0233     const Data& operator*() const
0234     {
0235         Q_ASSERT(m_match != -1);
0236         return this->m_data[m_match];
0237     }
0238 
0239     ConvenientEmbeddedSetFilterIterator& operator++()
0240     {
0241         Q_ASSERT(m_match != -1);
0242         go();
0243         return *this;
0244     }
0245         #define CHECK_BOUNDS Q_ASSERT( \
0246         boundStack.back().first.first < 100000 && boundStack.back().first.second < 10000  && boundStack.back().second.first < 100000 && \
0247         boundStack.back().second.second < 10000);
0248 
0249 private:
0250     void go()
0251     {
0252         m_match = -1;
0253 
0254 boundsUp:
0255         if (boundStack.isEmpty())
0256             return;
0257         CHECK_BOUNDS
0258         QPair<QPair<uint, uint>, QPair<uint, uint>> currentBounds = boundStack.back();
0259         boundStack.pop_back();
0260 
0261         uint ownStart = currentBounds.first.first, ownEnd = currentBounds.first.second;
0262         uint rhsStart = currentBounds.second.first, rhsEnd = currentBounds.second.second;
0263 #if 0
0264         //This code works, but it doesn't give a speedup
0265         int ownFirstValid = this->firstValidItem(ownStart, ownEnd),
0266             ownLastValid = this->lastValidItem(ownStart, ownEnd);
0267         int rhsFirstValid = m_rhs.firstValidItem(rhsStart, rhsEnd),
0268             rhsLastValid = m_rhs.lastValidItem(rhsStart, rhsEnd);
0269 
0270         if (ownFirstValid == -1 || rhsFirstValid == -1)
0271             goto boundsUp;
0272 
0273         Data2 ownFirstValidData = KeyExtractor::extract(this->m_data[ownFirstValid]);
0274         Data2 ownLastValidData = KeyExtractor::extract(this->m_data[ownLastValid]);
0275 
0276         Data2 commonStart = ownFirstValidData;
0277         Data2 commonLast = ownLastValidData;     //commonLast is also still valid
0278 
0279         if (commonStart < m_rhs.m_data[rhsFirstValid])
0280             commonStart = m_rhs.m_data[rhsFirstValid];
0281 
0282         if (m_rhs.m_data[rhsLastValid] < commonLast)
0283             commonLast = m_rhs.m_data[rhsLastValid];
0284 
0285         if (commonLast < commonStart)
0286             goto boundsUp;
0287 #endif
0288 
0289         while (true) {
0290             if (ownStart == ownEnd)
0291                 goto boundsUp;
0292 
0293             int ownMiddle = this->validMiddle(ownStart, ownEnd);
0294             Q_ASSERT(ownMiddle < 100000);
0295             if (ownMiddle == -1)
0296                 goto boundsUp;     //No valid items in the range
0297 
0298             Data2 currentData2 = KeyExtractor::extract(this->m_data[ownMiddle]);
0299             Q_ASSERT(!Handler2::isFree(currentData2));
0300 
0301             int bound = m_rhs.lowerBound(currentData2, rhsStart, rhsEnd);
0302             if (bound == -1) {
0303                 //Release second half of the own range
0304 //                     Q_ASSERT(ownEnd > ownMiddle);
0305                 ownEnd = ownMiddle;
0306                 continue;
0307             }
0308 
0309             if (currentData2 == m_rhs.m_data[bound]) {
0310                 //We have a match
0311                 this->m_match = ownMiddle;
0312                 //Append the ranges that need to be matched next, without the matched item
0313                 boundStack.append(qMakePair(qMakePair(( uint )ownMiddle + 1, ownEnd),
0314                                             qMakePair(( uint )bound, rhsEnd)));
0315                 if (ownMiddle)
0316                     boundStack.append(qMakePair(qMakePair(ownStart, ( uint )ownMiddle),
0317                                                 qMakePair(rhsStart, ( uint )bound + 1)));
0318                 return;
0319             }
0320 
0321             if (bound == m_rhs.firstValidItem(rhsStart)) {
0322                 //The bound is the first valid item of the second range.
0323                 //Discard left side and the matched left item, and continue.
0324 
0325                 ownStart = ownMiddle + 1;
0326                 rhsStart = bound;
0327                 continue;
0328             }
0329 
0330             //Standard: Split both sides into 2 ranges that will be checked next
0331             boundStack.append(qMakePair(qMakePair(( uint )ownMiddle + 1, ownEnd), qMakePair(( uint )bound, rhsEnd)));
0332 //                 Q_ASSERT(ownMiddle <= ownEnd);
0333             ownEnd = ownMiddle;     //We loose the item at 'middle' here, but that's fine, since it hasn't found a match.
0334             rhsEnd = bound + 1;
0335         }
0336     }
0337 
0338     //Bounds that yet need to be matched.
0339     KDevVarLengthArray<QPair<QPair<uint, uint>, QPair<uint, uint>>> boundStack;
0340     ConvenientEmbeddedSetIterator<Data2, Handler2> m_rhs;
0341     int m_match = -1;
0342 };
0343 
0344 ///Filters a list-embedded set by a binary tree set as managed by the SetRepository data structures
0345 template<class Data, class Handler, class Data2, class TreeSet, class KeyExtractor>
0346 class ConvenientEmbeddedSetTreeFilterIterator : public ConvenientEmbeddedSetIterator<Data
0347         , Handler>
0348 {
0349 public:
0350     ConvenientEmbeddedSetTreeFilterIterator()
0351     {
0352     }
0353     ///@param noFiltering whether the given input is pre-filtered. If this is true, base will be iterated without skipping any items.
0354     ConvenientEmbeddedSetTreeFilterIterator(const ConvenientEmbeddedSetIterator<Data, Handler>& base,
0355                                             const TreeSet& rhs,
0356                                             bool noFiltering = false) : ConvenientEmbeddedSetIterator<Data, Handler>(
0357             base)
0358         , m_rhs(rhs)
0359         , m_match(-1)
0360         , m_noFiltering(noFiltering)
0361     {
0362         if (rhs.node().isValid()) {
0363             //Correctly initialize the initial bounds
0364             int ownStart = lowerBound(rhs.node().firstItem(), 0, this->m_dataSize);
0365             if (ownStart == -1)
0366                 return;
0367             int ownEnd = lowerBound(rhs.node().lastItem(), ownStart, this->m_dataSize);
0368             if (ownEnd == -1)
0369                 ownEnd = this->m_dataSize;
0370             else
0371                 ownEnd += 1;
0372             boundStack.append(qMakePair(qMakePair(( uint )ownStart, ( uint )ownEnd), rhs.node()));
0373         }
0374         go();
0375     }
0376 
0377     operator bool() const {
0378         return m_match != -1;
0379     }
0380 
0381     const Data* operator->() const
0382     {
0383         Q_ASSERT(m_match != -1);
0384         return &this->m_data[m_match];
0385     }
0386 
0387     const Data& operator*() const
0388     {
0389         Q_ASSERT(m_match != -1);
0390         return this->m_data[m_match];
0391     }
0392 
0393     ConvenientEmbeddedSetTreeFilterIterator& operator++()
0394     {
0395         Q_ASSERT(m_match != -1);
0396         go();
0397         return *this;
0398     }
0399         #define CHECK_BOUNDS Q_ASSERT( \
0400         boundStack.back().first.first < 100000 && boundStack.back().first.second < 10000  && boundStack.back().second.first < 100000 && \
0401         boundStack.back().second.second < 10000);
0402 
0403 private:
0404     void go()
0405     {
0406         if (m_noFiltering) {
0407             ++m_match;
0408             if (( uint )m_match >= this->m_dataSize)
0409                 m_match = -1;
0410             return;
0411         }
0412 
0413         if (m_match != -1) {
0414             //Match multiple items in this list to one in the tree
0415             m_match = this->firstValidItem(m_match + 1, this->m_dataSize);
0416             if (m_match != -1 && KeyExtractor::extract(this->m_data[m_match]) == m_matchingTo)
0417                 return;
0418         }
0419         m_match = -1;
0420 
0421 boundsUp:
0422         if (boundStack.isEmpty())
0423             return;
0424         QPair<QPair<uint, uint>, typename TreeSet::Node> currentBounds = boundStack.back();
0425         boundStack.pop_back();
0426 
0427         uint ownStart = currentBounds.first.first, ownEnd = currentBounds.first.second;
0428         typename TreeSet::Node currentNode = currentBounds.second;
0429 
0430         if (ownStart >= ownEnd)
0431             goto boundsUp;
0432         if (!currentNode.isValid())
0433             goto boundsUp;
0434 
0435         while (true) {
0436             if (ownStart == ownEnd)
0437                 goto boundsUp;
0438 
0439             if (currentNode.isFinalNode()) {
0440 //                      qCDebug(UTIL) << ownStart << ownEnd << "final node" << currentNode.start() * extractor_div_with << currentNode.end() * extractor_div_with;
0441                 //Check whether the item is contained
0442                 int bound = lowerBound(*currentNode, ownStart, ownEnd);
0443 //                      qCDebug(UTIL) << "bound:" << bound << (KeyExtractor::extract(this->m_data[bound]) == *currentNode);
0444                 if (bound != -1 && KeyExtractor::extract(this->m_data[bound]) == *currentNode) {
0445                     //Got a match
0446                     m_match = bound;
0447                     m_matchingTo = *currentNode;
0448                     m_matchBound = ownEnd;
0449                     return;
0450                 } else {
0451                     //Mismatch
0452                     goto boundsUp;
0453                 }
0454             } else {
0455 //                     qCDebug(UTIL) << ownStart << ownEnd << "node" << currentNode.start() * extractor_div_with << currentNode.end() * extractor_div_with;
0456                 //This is not a final node, split up the search into the sub-nodes
0457                 typename TreeSet::Node leftNode = currentNode.leftChild();
0458                 typename TreeSet::Node rightNode = currentNode.rightChild();
0459                 Q_ASSERT(leftNode.isValid());
0460                 Q_ASSERT(rightNode.isValid());
0461 
0462                 Data2 leftLastItem = leftNode.lastItem();
0463 
0464                 int rightSearchStart = lowerBound(rightNode.firstItem(), ownStart, ownEnd);
0465                 if (rightSearchStart == -1)
0466                     rightSearchStart = ownEnd;
0467                 int leftSearchLast = lowerBound(leftLastItem, ownStart,
0468                                                 rightSearchStart != -1 ? rightSearchStart : ownEnd);
0469                 if (leftSearchLast == -1)
0470                     leftSearchLast = rightSearchStart - 1;
0471 
0472                 bool recurseLeft = false;
0473                 if (leftSearchLast > ( int )ownStart) {
0474                     recurseLeft = true;     //There must be something in the range ownStart -> leftSearchLast that matches the range
0475                 } else if (( int )ownStart == leftSearchLast) {
0476                     //Check if the one item under leftSearchStart is contained in the range
0477                     Data2 leftFoundStartData = KeyExtractor::extract(this->m_data[ownStart]);
0478                     recurseLeft = leftFoundStartData < leftLastItem || leftFoundStartData == leftLastItem;
0479                 }
0480 
0481                 bool recurseRight = false;
0482                 if (rightSearchStart < ( int )ownEnd)
0483                     recurseRight = true;
0484 
0485                 if (recurseLeft && recurseRight) {
0486                     //Push the right branch onto the stack, and work in the left one
0487                     boundStack.append(qMakePair(qMakePair(( uint )rightSearchStart, ownEnd), rightNode));
0488                 }
0489 
0490                 if (recurseLeft) {
0491                     currentNode = leftNode;
0492                     if (leftSearchLast != -1)
0493                         ownEnd = leftSearchLast + 1;
0494                 } else if (recurseRight) {
0495                     currentNode = rightNode;
0496                     ownStart = rightSearchStart;
0497                 } else {
0498                     goto boundsUp;
0499                 }
0500             }
0501         }
0502     }
0503 
0504     ///Returns the first valid index that has an extracted data-value larger or equal to @p data.
0505     ///Returns -1 if nothing is found.
0506     int lowerBound(const Data2& data, int start, int end)
0507     {
0508         int currentBound = -1;
0509         while (1) {
0510             if (start >= end)
0511                 return currentBound;
0512 
0513             int center = (start + end) / 2;
0514 
0515             //Skip free items, since they cannot be used for ordering
0516             for (; center < end;) {
0517                 if (!Handler::isFree(this->m_data[center]))
0518                     break;
0519                 ++center;
0520             }
0521 
0522             if (center == end) {
0523                 end = (start + end) / 2;   //No non-free items found in second half, so continue search in the other
0524             } else {
0525                 Data2 centerData = KeyExtractor::extract(this->m_data[center]);
0526                 //Even if the data equals we must continue searching to the left, since there may be multiple matching
0527                 if (data == centerData || data < centerData) {
0528                     currentBound = center;
0529                     end = (start + end) / 2;
0530                 } else {
0531                     //Continue search in second half
0532                     start = center + 1;
0533                 }
0534             }
0535         }
0536     }
0537 
0538     //Bounds that yet need to be matched. Always a range in the own vector, and a node that all items in the range are contained in
0539     KDevVarLengthArray<QPair<QPair<uint, uint>, typename TreeSet::Node>> boundStack;
0540     TreeSet m_rhs;
0541     int m_match = -1, m_matchBound;
0542     Data2 m_matchingTo;
0543     bool m_noFiltering;
0544 };
0545 
0546 ///Same as above, except that it visits all filtered items with a visitor, instead of iterating over them.
0547 ///This is more efficient. The visiting is done directly from within the constructor.
0548 template<class Data, class Handler, class Data2, class TreeSet, class KeyExtractor, class Visitor>
0549 class ConvenientEmbeddedSetTreeFilterVisitor : public ConvenientEmbeddedSetIterator<Data
0550         , Handler>
0551 {
0552 public:
0553     ConvenientEmbeddedSetTreeFilterVisitor()
0554     {
0555     }
0556 
0557     using Bounds = QPair<QPair<uint, uint>, typename TreeSet::Node>;
0558 
0559     struct Bound
0560     {
0561         inline Bound(uint s, uint e, const typename TreeSet::Node& n) : start(s)
0562             , end(e)
0563             , node(n)
0564         {
0565         }
0566         Bound()
0567         {
0568         }
0569         uint start;
0570         uint end;
0571         typename TreeSet::Node node;
0572     };
0573 
0574     ///@param noFiltering whether the given input is pre-filtered. If this is true, base will be iterated without skipping any items.
0575     ConvenientEmbeddedSetTreeFilterVisitor(Visitor& visitor, const ConvenientEmbeddedSetIterator<Data, Handler>& base,
0576                                            const TreeSet& rhs,
0577                                            bool noFiltering = false) : ConvenientEmbeddedSetIterator<Data,
0578             Handler>(base)
0579         , m_visitor(visitor)
0580         , m_rhs(rhs)
0581         , m_noFiltering(noFiltering)
0582     {
0583 
0584         if (m_noFiltering) {
0585             for (uint a = 0; a < this->m_dataSize; ++a)
0586                 visitor(this->m_data[a]);
0587 
0588             return;
0589         }
0590 
0591         if (rhs.node().isValid()) {
0592             //Correctly initialize the initial bounds
0593             int ownStart = lowerBound(rhs.node().firstItem(), 0, this->m_dataSize);
0594             if (ownStart == -1)
0595                 return;
0596             int ownEnd = lowerBound(rhs.node().lastItem(), ownStart, this->m_dataSize);
0597             if (ownEnd == -1)
0598                 ownEnd = this->m_dataSize;
0599             else
0600                 ownEnd += 1;
0601 
0602             go(Bound(( uint )ownStart, ( uint )ownEnd, rhs.node()));
0603         }
0604     }
0605 
0606 private:
0607     void go(Bound bound)
0608     {
0609 
0610         KDevVarLengthArray<Bound> bounds;
0611 
0612         while (true) {
0613             if (bound.start >= bound.end)
0614                 goto nextBound;
0615 
0616             if (bound.node.isFinalNode()) {
0617                 //Check whether the item is contained
0618                 int b = lowerBound(*bound.node, bound.start, bound.end);
0619                 if (b != -1) {
0620                     const Data2& matchTo(*bound.node);
0621 
0622                     if (KeyExtractor::extract(this->m_data[b]) == matchTo) {
0623                         while (1) {
0624                             m_visitor(this->m_data[b]);
0625                             b = this->firstValidItem(b + 1, this->m_dataSize);
0626                             if (b < ( int )this->m_dataSize && b != -1 &&
0627                                 KeyExtractor::extract(this->m_data[b]) == matchTo)
0628                                 continue;
0629                             else
0630                                 break;
0631                         }
0632                     }
0633                 }
0634                 goto nextBound;
0635             } else {
0636                 //This is not a final node, split up the search into the sub-nodes
0637                 typename TreeSet::Node leftNode = bound.node.leftChild();
0638                 typename TreeSet::Node rightNode = bound.node.rightChild();
0639                 Q_ASSERT(leftNode.isValid());
0640                 Q_ASSERT(rightNode.isValid());
0641 
0642                 Data2 leftLastItem = leftNode.lastItem();
0643 
0644                 int rightSearchStart = lowerBound(rightNode.firstItem(), bound.start, bound.end);
0645                 if (rightSearchStart == -1)
0646                     rightSearchStart = bound.end;
0647                 int leftSearchLast = lowerBound(leftLastItem, bound.start,
0648                                                 rightSearchStart != -1 ? rightSearchStart : bound.end);
0649                 if (leftSearchLast == -1)
0650                     leftSearchLast = rightSearchStart - 1;
0651 
0652                 bool recurseLeft = false;
0653                 if (leftSearchLast > ( int )bound.start) {
0654                     recurseLeft = true;     //There must be something in the range bound.start -> leftSearchLast that matches the range
0655                 } else if (( int )bound.start == leftSearchLast) {
0656                     //Check if the one item under leftSearchStart is contained in the range
0657                     Data2 leftFoundStartData = KeyExtractor::extract(this->m_data[bound.start]);
0658                     recurseLeft = leftFoundStartData < leftLastItem || leftFoundStartData == leftLastItem;
0659                 }
0660 
0661                 bool recurseRight = false;
0662                 if (rightSearchStart < ( int )bound.end)
0663                     recurseRight = true;
0664 
0665                 if (recurseLeft && recurseRight)
0666                     bounds.append(Bound(rightSearchStart, bound.end, rightNode));
0667 
0668                 if (recurseLeft) {
0669                     bound.node = leftNode;
0670                     if (leftSearchLast != -1)
0671                         bound.end = leftSearchLast + 1;
0672                 } else if (recurseRight) {
0673                     bound.node = rightNode;
0674                     bound.start = rightSearchStart;
0675                 } else {
0676                     goto nextBound;
0677                 }
0678                 continue;
0679             }
0680 nextBound:
0681             if (bounds.isEmpty()) {
0682                 return;
0683             } else {
0684                 bound = bounds.back();
0685                 bounds.pop_back();
0686             }
0687         }
0688     }
0689 
0690     ///Returns the first valid index that has an extracted data-value larger or equal to @p data.
0691     ///Returns -1 if nothing is found.
0692     int lowerBound(const Data2& data, int start, int end)
0693     {
0694         int currentBound = -1;
0695         while (1) {
0696             if (start >= end)
0697                 return currentBound;
0698 
0699             int center = (start + end) / 2;
0700 
0701             //Skip free items, since they cannot be used for ordering
0702             for (; center < end;) {
0703                 if (!Handler::isFree(this->m_data[center]))
0704                     break;
0705                 ++center;
0706             }
0707 
0708             if (center == end) {
0709                 end = (start + end) / 2;   //No non-free items found in second half, so continue search in the other
0710             } else {
0711                 Data2 centerData = KeyExtractor::extract(this->m_data[center]);
0712                 //Even if the data equals we must continue searching to the left, since there may be multiple matching
0713                 if (data == centerData || data < centerData) {
0714                     currentBound = center;
0715                     end = (start + end) / 2;
0716                 } else {
0717                     //Continue search in second half
0718                     start = center + 1;
0719                 }
0720             }
0721         }
0722     }
0723 
0724     //Bounds that yet need to be matched. Always a range in the own vector, and a node that all items in the range are contained in
0725     Visitor& m_visitor;
0726     TreeSet m_rhs;
0727     bool m_noFiltering;
0728 };
0729 
0730 template<class Data, class Handler>
0731 ConvenientEmbeddedSetIterator<Data, Handler> ConstantConvenientEmbeddedSet<Data, Handler>::iterator() const
0732 {
0733     return ConvenientEmbeddedSetIterator<Data, Handler>(m_data, m_dataSize, m_centralFreeItem);
0734 }
0735 
0736 ///This is a simple set implementation based on the embedded free tree algorithms.
0737 ///The core advantage of the whole thing is that the wole set is represented by a consecutive
0738 ///memory-area, and thus can be stored or copied using a simple memcpy.
0739 ///However in many cases it's better using the algorithms directly in such cases.
0740 ///
0741 ///However even for normal tasks this implementation does have some advantages over std::set:
0742 ///- Many times faster iteration through contained data
0743 ///- Lower memory-usage if the objects are small, since there is no heap allocation overhead
0744 ///- Can be combined with other embedded-free-list based sets using algorithms in ConstantConvenientEmbeddedSet
0745 ///Disadvantages:
0746 ///- Significantly slower insertion
0747 
0748 template<class Data, class Handler>
0749 class ConvenientFreeListSet
0750 {
0751 public:
0752 
0753     using Iterator = ConvenientEmbeddedSetIterator<Data, Handler>;
0754 
0755     ConvenientFreeListSet()
0756     {
0757     }
0758 
0759     ///Re-construct a set from its components
0760     ConvenientFreeListSet(int centralFreeItem, QVector<Data> data) : m_data(data)
0761         , m_centralFree(centralFreeItem)
0762     {
0763     }
0764 
0765     ///You can use this to store the set to disk and later give it together with data() to the constructor,  thus reconstructing it.
0766     int centralFreeItem() const
0767     {
0768         return m_centralFree;
0769     }
0770 
0771     const QVector<Data>& data() const
0772     {
0773         return m_data;
0774     }
0775 
0776     void insert(const Data& item)
0777     {
0778         if (contains(item))
0779             return;
0780         KDevelop::EmbeddedTreeAddItem<Data, Handler> add(m_data.data(), m_data.size(), m_centralFree, item);
0781 
0782         if (( int )add.newItemCount() != ( int )m_data.size()) {
0783             QVector<Data> newData;
0784             newData.resize(add.newItemCount());
0785             add.transferData(newData.data(), newData.size());
0786             m_data = newData;
0787         }
0788     }
0789 
0790     Iterator iterator() const
0791     {
0792         return Iterator(m_data.data(), m_data.size(), m_centralFree);
0793     }
0794 
0795     bool contains(const Data& item) const
0796     {
0797         KDevelop::EmbeddedTreeAlgorithms<Data, Handler> alg(m_data.data(), m_data.size(), m_centralFree);
0798         return alg.indexOf(Data(item)) != -1;
0799     }
0800 
0801     void remove(const Data& item)
0802     {
0803         KDevelop::EmbeddedTreeRemoveItem<Data, Handler> remove(m_data.data(), m_data.size(), m_centralFree, item);
0804 
0805         if (( int )remove.newItemCount() != ( int )m_data.size()) {
0806             QVector<Data> newData;
0807             newData.resize(remove.newItemCount());
0808             remove.transferData(newData.data(), newData.size());
0809             m_data = newData;
0810         }
0811     }
0812 
0813 private:
0814     int m_centralFree = -1;
0815     QVector<Data> m_data;
0816 };
0817 }
0818 
0819 #endif