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