File indexing completed on 2024-05-12 04:38:09
0001 /* 0002 SPDX-FileCopyrightText: 2007 David Nolden <david.nolden.kdevelop@art-master.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "setrepository.h" 0008 #include <debug.h> 0009 #include <list> 0010 #include <util/kdevvarlengtharray.h> 0011 #include <iostream> 0012 #include <limits> 0013 #include <serialization/itemrepository.h> 0014 #include <serialization/indexedstring.h> 0015 #include <QString> 0016 #include <QMutex> 0017 #include <algorithm> 0018 0019 //#define DEBUG_SETREPOSITORY 0020 0021 #ifdef DEBUG_SETREPOSITORY 0022 #define ifDebug(X) X 0023 #else 0024 #define ifDebug(x) 0025 #undef Q_ASSERT 0026 #define Q_ASSERT(x) 0027 #endif 0028 0029 #ifndef DEBUG_SETREPOSITORY 0030 #define CHECK_SPLIT_POSITION(Node) 0031 #else 0032 #define CHECK_SPLIT_POSITION(node) Q_ASSERT(!(node).leftNode || \ 0033 (getLeftNode(&node)->end() <= \ 0034 splitPositionForRange((node).start, \ 0035 (node).end) && \ 0036 getRightNode(&node)->start() >= \ 0037 splitPositionForRange((node).start, (node).end))) 0038 #endif 0039 0040 namespace Utils { 0041 /** 0042 * To achieve a maximum re-usage of nodes, we make sure that sub-nodes of a node always split at specific boundaries. 0043 * For each range we can compute a position where that range should be split into its child-nodes. 0044 * When creating a new node with 2 sub-nodes, we re-create those child-nodes if their boundaries don't represent those split-positions. 0045 * 0046 * We pick the split-positions deterministically, they are in order of priority: 0047 * ((1<<31)*n, n = [0,...] 0048 * ((1<<30)*n, n = [0,...] 0049 * ((1<<29)*n, n = [0,...] 0050 * ((1<<...)*n, n = [0,...] 0051 * ... 0052 * */ 0053 0054 using Index = BasicSetRepository::Index; 0055 0056 ///The returned split position shall be the end of the first sub-range, and the start of the second 0057 ///@param splitBit should be initialized with 31, unless you know better. The value can then be used on while computing child split positions. 0058 ///In the end, it will contain the bit used to split the range. It will also contain zero if no split-position exists(length 1) 0059 uint splitPositionForRange(uint start, uint end, uchar& splitBit) 0060 { 0061 if (end - start == 1) { 0062 splitBit = 0; 0063 return 0; 0064 } 0065 0066 while (true) { 0067 uint position = ((end - 1) >> splitBit) << splitBit; //Round to the split-position in this interval that is smaller than end 0068 if (position > start && position < end) 0069 return position; 0070 Q_ASSERT(splitBit != 0); 0071 --splitBit; 0072 } 0073 0074 return 0; 0075 } 0076 0077 uint splitPositionForRange(uint start, uint end) 0078 { 0079 uchar splitBit = 31; 0080 return splitPositionForRange(start, end, splitBit); 0081 } 0082 0083 class SetNodeDataRequest; 0084 0085 #define getLeftNode(node) repository.itemFromIndex(node->leftNode()) 0086 #define getRightNode(node) repository.itemFromIndex(node->rightNode()) 0087 #define nodeFromIndex(index) repository.itemFromIndex(index) 0088 struct SetRepositoryAlgorithms 0089 { 0090 SetRepositoryAlgorithms(SetDataRepository& _repository, 0091 BasicSetRepository* _setRepository) : repository(_repository) 0092 , setRepository(_setRepository) 0093 { 0094 } 0095 0096 ///Expensive 0097 Index count(const SetNodeData* node) const; 0098 0099 void localCheck(const SetNodeData* node); 0100 0101 void check(uint node); 0102 0103 void check(const SetNodeData* node); 0104 0105 QString shortLabel(const SetNodeData& node) const; 0106 0107 uint set_union(uint firstNode, uint secondNode, const SetNodeData* first, const SetNodeData* second, 0108 uchar splitBit = 31); 0109 uint createSetFromNodes(uint leftNode, uint rightNode, const SetNodeData* left = nullptr, 0110 const SetNodeData* right = nullptr); 0111 uint computeSetFromNodes(uint leftNode, uint rightNode, const SetNodeData* left, const SetNodeData* right, 0112 uchar splitBit); 0113 uint set_intersect(uint firstNode, uint secondNode, const SetNodeData* first, const SetNodeData* second, 0114 uchar splitBit = 31); 0115 bool set_contains(const SetNodeData* node, Index index); 0116 uint set_subtract(uint firstNode, uint secondNode, const SetNodeData* first, const SetNodeData* second, 0117 uchar splitBit = 31); 0118 0119 //Required both nodes to be split correctly 0120 bool set_equals(const SetNodeData* lhs, const SetNodeData* rhs); 0121 0122 QString dumpDotGraph(uint node) const; 0123 0124 ///Finds or inserts the given ranges into the repository, and returns the set-index that represents them 0125 uint setForIndices(std::vector<uint>::const_iterator begin, std::vector<uint>::const_iterator end, 0126 uchar splitBit = 31) 0127 { 0128 Q_ASSERT(begin != end); 0129 0130 uint startIndex = *begin; 0131 uint endIndex = *(end - 1) + 1; 0132 0133 if (endIndex == startIndex + 1) { 0134 SetNodeData data(startIndex, endIndex); 0135 0136 return repository.index(SetNodeDataRequest(&data, repository, setRepository)); 0137 } 0138 0139 uint split = splitPositionForRange(startIndex, endIndex, splitBit); 0140 Q_ASSERT(split); 0141 0142 auto splitIterator = std::lower_bound(begin, end, split); 0143 Q_ASSERT(*splitIterator >= split); 0144 Q_ASSERT(splitIterator > begin); 0145 Q_ASSERT(*(splitIterator - 1) < split); 0146 0147 return createSetFromNodes(setForIndices(begin, splitIterator, splitBit), 0148 setForIndices(splitIterator, end, splitBit)); 0149 } 0150 0151 private: 0152 QString dumpDotGraphInternal(uint node, bool master = false) const; 0153 0154 SetDataRepository& repository; 0155 BasicSetRepository* setRepository; 0156 }; 0157 0158 void SetNodeDataRequest::destroy(SetNodeData* data, KDevelop::AbstractItemRepository& _repository) 0159 { 0160 auto& repository(static_cast<SetDataRepository&>(_repository)); 0161 0162 if (repository.setRepository->delayedDeletion()) { 0163 if (data->leftNode()) { 0164 SetDataRepositoryBase::MyDynamicItem left = repository.dynamicItemFromIndex(data->leftNode()); 0165 SetDataRepositoryBase::MyDynamicItem right = repository.dynamicItemFromIndex(data->rightNode()); 0166 Q_ASSERT(left->m_refCount > 0); 0167 --left->m_refCount; 0168 Q_ASSERT(right->m_refCount > 0); 0169 --right->m_refCount; 0170 } else { 0171 //Deleting a leaf 0172 Q_ASSERT(data->end() - data->start() == 1); 0173 repository.setRepository->itemRemovedFromSets(data->start()); 0174 } 0175 } 0176 } 0177 0178 SetNodeDataRequest::SetNodeDataRequest(const SetNodeData* _data, SetDataRepository& _repository, 0179 BasicSetRepository* _setRepository) : data(*_data) 0180 , m_hash(_data->hash()) 0181 , repository(_repository) 0182 , setRepository(_setRepository) 0183 , m_created(false) 0184 { 0185 ifDebug(SetRepositoryAlgorithms alg(repository); alg.check(_data)); 0186 } 0187 0188 SetNodeDataRequest::~SetNodeDataRequest() 0189 { 0190 //Eventually increase the reference-count of direct children 0191 if (m_created) { 0192 if (data.leftNode()) 0193 ++repository.dynamicItemFromIndex(data.leftNode())->m_refCount; 0194 if (data.rightNode()) 0195 ++repository.dynamicItemFromIndex(data.rightNode())->m_refCount; 0196 } 0197 } 0198 0199 //Should create an item where the information of the requested item is permanently stored. The pointer 0200 //@param item equals an allocated range with the size of itemSize(). 0201 void SetNodeDataRequest::createItem(SetNodeData* item) const 0202 { 0203 Q_ASSERT((data.rightNode() && data.leftNode()) || (!data.rightNode() && !data.leftNode())); 0204 0205 m_created = true; 0206 0207 *item = data; 0208 0209 Q_ASSERT((item->rightNode() && item->leftNode()) || (!item->rightNode() && !item->leftNode())); 0210 0211 #ifdef DEBUG_SETREPOSITORY 0212 //Make sure we split at the correct split position 0213 if (item->hasSlaves()) { 0214 uint split = splitPositionForRange(data.start, data.end); 0215 const SetNodeData* left = repository.itemFromIndex(item->leftNode()); 0216 const SetNodeData* right = repository.itemFromIndex(item->rightNode()); 0217 Q_ASSERT(split >= left->end() && split <= right->start()); 0218 } 0219 #endif 0220 if (!data.leftNode() && setRepository) { 0221 for (uint a = item->start(); a < item->end(); ++a) 0222 setRepository->itemAddedToSets(a); 0223 } 0224 } 0225 0226 bool SetNodeDataRequest::equals(const SetNodeData* item) const 0227 { 0228 Q_ASSERT((item->rightNode() && item->leftNode()) || (!item->rightNode() && !item->leftNode())); 0229 //Just compare child nodes, since data must be correctly split, this is perfectly ok 0230 //Since this happens in very tight loops, we don't call an additional function here, but just do the check. 0231 return item->leftNode() == data.leftNode() && item->rightNode() == data.rightNode() && 0232 item->start() == data.start() && item->end() == data.end(); 0233 } 0234 0235 Set::Set() 0236 { 0237 } 0238 0239 Set::~Set() 0240 { 0241 } 0242 0243 unsigned int Set::count() const 0244 { 0245 if (!m_repository || !m_tree) 0246 return 0; 0247 QMutexLocker lock(m_repository->m_mutex); 0248 0249 SetRepositoryAlgorithms alg(m_repository->m_dataRepository, m_repository); 0250 return alg.count(m_repository->m_dataRepository.itemFromIndex(m_tree)); 0251 } 0252 0253 Set::Set(uint treeNode, BasicSetRepository* repository) : m_tree(treeNode) 0254 , m_repository(repository) 0255 { 0256 } 0257 0258 Set::Set(const Set& rhs) 0259 { 0260 m_repository = rhs.m_repository; 0261 m_tree = rhs.m_tree; 0262 } 0263 0264 Set& Set::operator=(const Set& rhs) 0265 { 0266 m_repository = rhs.m_repository; 0267 m_tree = rhs.m_tree; 0268 return *this; 0269 } 0270 0271 QString Set::dumpDotGraph() const 0272 { 0273 if (!m_repository || !m_tree) 0274 return QString(); 0275 0276 QMutexLocker lock(m_repository->m_mutex); 0277 0278 SetRepositoryAlgorithms alg(m_repository->m_dataRepository, m_repository); 0279 return alg.dumpDotGraph(m_tree); 0280 } 0281 0282 Index SetRepositoryAlgorithms::count(const SetNodeData* node) const 0283 { 0284 if (node->leftNode() && node->rightNode()) 0285 return count(getLeftNode(node)) + count(getRightNode(node)); 0286 else 0287 return node->end() - node->start(); 0288 } 0289 0290 void SetRepositoryAlgorithms::localCheck(const SetNodeData* ifDebug(node)) 0291 { 0292 // Q_ASSERT(node->start() > 0); 0293 Q_ASSERT(node->start() < node->end()); 0294 Q_ASSERT((node->leftNode() && node->rightNode()) || (!node->leftNode() && !node->rightNode())); 0295 Q_ASSERT(!node->leftNode() || 0296 (getLeftNode(node())->start() == node->start() && getRightNode(node)->end() == node->end())); 0297 Q_ASSERT(!node->leftNode() || (getLeftNode(node())->end() <= getRightNode(node)->start())); 0298 } 0299 0300 void SetRepositoryAlgorithms::check(uint node) 0301 { 0302 if (!node) 0303 return; 0304 0305 check(nodeFromIndex(node)); 0306 } 0307 0308 void SetRepositoryAlgorithms::check(const SetNodeData* node) 0309 { 0310 localCheck(node); 0311 if (node->leftNode()) 0312 check(getLeftNode(node)); 0313 if (node->rightNode()) 0314 check(getRightNode(node)); 0315 // CHECK_SPLIT_POSITION(*node); Re-enable this 0316 } 0317 0318 QString SetRepositoryAlgorithms::shortLabel(const SetNodeData& node) const 0319 { 0320 return QStringLiteral("n%1_%2").arg(node.start()).arg(node.end()); 0321 } 0322 0323 QString SetRepositoryAlgorithms::dumpDotGraphInternal(uint nodeIndex, bool master) const 0324 { 0325 if (!nodeIndex) 0326 return QStringLiteral("empty node"); 0327 0328 const SetNodeData& node(*repository.itemFromIndex(nodeIndex)); 0329 0330 QString color = QStringLiteral("blue"); 0331 if (master) 0332 color = QStringLiteral("red"); 0333 0334 QString label = QStringLiteral("%1 -> %2").arg(node.start()).arg(node.end()); 0335 if (!node.contiguous()) 0336 label += QLatin1String(", with gaps"); 0337 0338 QString ret = QStringLiteral("%1[label=\"%2\", color=\"%3\"];\n").arg(shortLabel(node), label, color); 0339 0340 if (node.leftNode()) { 0341 const SetNodeData& left(*repository.itemFromIndex(node.leftNode())); 0342 const SetNodeData& right(*repository.itemFromIndex(node.rightNode())); 0343 Q_ASSERT(node.rightNode()); 0344 ret += QStringLiteral("%1 -> %2;\n").arg(shortLabel(node), shortLabel(left)); 0345 ret += QStringLiteral("%1 -> %2;\n").arg(shortLabel(node), shortLabel(right)); 0346 ret += dumpDotGraphInternal(node.leftNode()); 0347 ret += dumpDotGraphInternal(node.rightNode()); 0348 } 0349 0350 return ret; 0351 } 0352 0353 QString SetRepositoryAlgorithms::dumpDotGraph(uint nodeIndex) const 0354 { 0355 QString ret = QStringLiteral("digraph Repository {\n"); 0356 ret += dumpDotGraphInternal(nodeIndex, true); 0357 ret += QLatin1String("}\n"); 0358 return ret; 0359 } 0360 0361 const int nodeStackAlloc = 500; 0362 0363 class Set::IteratorPrivate 0364 { 0365 public: 0366 IteratorPrivate() 0367 { 0368 nodeStackData.resize(nodeStackAlloc); 0369 nodeStack = nodeStackData.data(); 0370 } 0371 0372 IteratorPrivate(const Set::IteratorPrivate& rhs) 0373 : nodeStackData(rhs.nodeStackData) 0374 , nodeStackSize(rhs.nodeStackSize) 0375 , currentIndex(rhs.currentIndex) 0376 , repository(rhs.repository) 0377 { 0378 nodeStack = nodeStackData.data(); 0379 } 0380 0381 Set::IteratorPrivate& operator=(const Set::IteratorPrivate& rhs) 0382 { 0383 nodeStackData = rhs.nodeStackData; 0384 nodeStackSize = rhs.nodeStackSize; 0385 currentIndex = rhs.currentIndex; 0386 repository = rhs.repository; 0387 nodeStack = nodeStackData.data(); 0388 0389 return *this; 0390 } 0391 0392 void resizeNodeStack() 0393 { 0394 nodeStackData.resize(nodeStackSize + 1); 0395 nodeStack = nodeStackData.data(); 0396 } 0397 0398 KDevVarLengthArray<const SetNodeData*, nodeStackAlloc> nodeStackData; 0399 const SetNodeData** nodeStack; 0400 int nodeStackSize = 0; 0401 Index currentIndex = 0; 0402 BasicSetRepository* repository = nullptr; 0403 0404 /** 0405 * Pushes the noed on top of the stack, changes currentIndex, and goes as deep as necessary for iteration. 0406 * */ 0407 void startAtNode(const SetNodeData* node) 0408 { 0409 Q_ASSERT(node->start() != node->end()); 0410 currentIndex = node->start(); 0411 0412 do { 0413 nodeStack[nodeStackSize++] = node; 0414 0415 if (nodeStackSize >= nodeStackAlloc) 0416 resizeNodeStack(); 0417 0418 if (node->contiguous()) 0419 break; //We need no finer granularity, because the range is contiguous 0420 node = Set::Iterator::getDataRepository(repository).itemFromIndex(node->leftNode()); 0421 } while (node); 0422 Q_ASSERT(currentIndex >= nodeStack[0]->start()); 0423 } 0424 }; 0425 0426 std::set<Index> Set::stdSet() const 0427 { 0428 Set::Iterator it = iterator(); 0429 std::set<Index> ret; 0430 0431 while (it) { 0432 Q_ASSERT(ret.find(*it) == ret.end()); 0433 ret.insert(*it); 0434 ++it; 0435 } 0436 0437 return ret; 0438 } 0439 0440 Set::Iterator::Iterator(const Iterator& rhs) 0441 : d_ptr(new Set::IteratorPrivate(*rhs.d_ptr)) 0442 { 0443 } 0444 0445 Set::Iterator& Set::Iterator::operator=(const Iterator& rhs) 0446 { 0447 *d_ptr = *rhs.d_ptr; 0448 return *this; 0449 } 0450 0451 Set::Iterator::Iterator() 0452 : d_ptr(new Set::IteratorPrivate) 0453 { 0454 } 0455 0456 Set::Iterator::~Iterator() = default; 0457 0458 Set::Iterator::operator bool() const 0459 { 0460 Q_D(const Iterator); 0461 0462 return d->nodeStackSize; 0463 } 0464 0465 Set::Iterator& Set::Iterator::operator++() 0466 { 0467 Q_D(Iterator); 0468 0469 Q_ASSERT(d->nodeStackSize); 0470 0471 if (d->repository->m_mutex) 0472 d->repository->m_mutex->lock(); 0473 0474 ++d->currentIndex; 0475 0476 //const SetNodeData** currentNode = &d->nodeStack[d->nodeStackSize - 1]; 0477 if (d->currentIndex >= d->nodeStack[d->nodeStackSize - 1]->end()) { 0478 //Advance to the next node 0479 while (d->nodeStackSize && d->currentIndex >= d->nodeStack[d->nodeStackSize - 1]->end()) { 0480 --d->nodeStackSize; 0481 } 0482 0483 if (!d->nodeStackSize) { 0484 //ready 0485 } else { 0486 //++d->nodeStackSize; 0487 //We were iterating the left slave of the node, now continue with the right. 0488 ifDebug(const SetNodeData& left = 0489 *d->repository->m_dataRepository.itemFromIndex( 0490 d->nodeStack[d->nodeStackSize - 1]->leftNode()); Q_ASSERT(left.end == d->currentIndex); ) 0491 0492 const SetNodeData& right = *d->repository->m_dataRepository.itemFromIndex( 0493 d->nodeStack[d->nodeStackSize - 1]->rightNode()); 0494 0495 d->startAtNode(&right); 0496 } 0497 } 0498 0499 Q_ASSERT(d->nodeStackSize == 0 || d->currentIndex < d->nodeStack[0]->end()); 0500 0501 if (d->repository->m_mutex) 0502 d->repository->m_mutex->unlock(); 0503 0504 return *this; 0505 } 0506 0507 BasicSetRepository::Index Set::Iterator::operator*() const 0508 { 0509 Q_D(const Iterator); 0510 0511 return d->currentIndex; 0512 } 0513 0514 Set::Iterator Set::iterator() const 0515 { 0516 if (!m_tree || !m_repository) 0517 return Iterator(); 0518 0519 QMutexLocker lock(m_repository->m_mutex); 0520 0521 Iterator ret; 0522 ret.d_ptr->repository = m_repository; 0523 0524 if (m_tree) 0525 ret.d_ptr->startAtNode(m_repository->m_dataRepository.itemFromIndex(m_tree)); 0526 return ret; 0527 } 0528 0529 //Creates a set item with the given children., they must be valid, and they must be split around their split-position. 0530 uint SetRepositoryAlgorithms::createSetFromNodes(uint leftNode, uint rightNode, const SetNodeData* left, 0531 const SetNodeData* right) 0532 { 0533 if (!left) 0534 left = nodeFromIndex(leftNode); 0535 if (!right) 0536 right = nodeFromIndex(rightNode); 0537 0538 Q_ASSERT(left->end() <= right->start()); 0539 0540 SetNodeData set(left->start(), right->end(), leftNode, rightNode); 0541 0542 Q_ASSERT(set.start() < set.end()); 0543 0544 uint ret = repository.index(SetNodeDataRequest(&set, repository, setRepository)); 0545 Q_ASSERT(set.leftNode() >= 0x10000); 0546 Q_ASSERT(set.rightNode() >= 0x10000); 0547 Q_ASSERT(ret == repository.findIndex(SetNodeDataRequest(&set, repository, setRepository))); 0548 ifDebug(check(ret)); 0549 return ret; 0550 } 0551 0552 //Constructs a set node from the given two sub-nodes. Those must be valid, they must not intersect, and they must have a correct split-hierarchy. 0553 //The do not need to be split around their computed split-position. 0554 uint SetRepositoryAlgorithms::computeSetFromNodes(uint leftNode, uint rightNode, const SetNodeData* left, 0555 const SetNodeData* right, uchar splitBit) 0556 { 0557 Q_ASSERT(left->end() <= right->start()); 0558 uint splitPosition = splitPositionForRange(left->start(), right->end(), splitBit); 0559 0560 Q_ASSERT(splitPosition); 0561 0562 if (splitPosition < left->end()) { 0563 //The split-position intersects the left node 0564 uint leftLeftNode = left->leftNode(); 0565 uint leftRightNode = left->rightNode(); 0566 0567 const SetNodeData* leftLeft = this->getLeftNode(left); 0568 const SetNodeData* leftRight = this->getRightNode(left); 0569 0570 Q_ASSERT(splitPosition >= leftLeft->end() && splitPosition <= leftRight->start()); 0571 0572 //Create a new set from leftLeft, and from leftRight + right. That set will have the correct split-position. 0573 uint newRightNode = computeSetFromNodes(leftRightNode, rightNode, leftRight, right, splitBit); 0574 0575 return createSetFromNodes(leftLeftNode, newRightNode, leftLeft); 0576 } else if (splitPosition > right->start()) { 0577 //The split-position intersects the right node 0578 uint rightLeftNode = right->leftNode(); 0579 uint rightRightNode = right->rightNode(); 0580 0581 const SetNodeData* rightLeft = this->getLeftNode(right); 0582 const SetNodeData* rightRight = this->getRightNode(right); 0583 0584 Q_ASSERT(splitPosition >= rightLeft->end() && splitPosition <= rightRight->start()); 0585 0586 //Create a new set from left + rightLeft, and from rightRight. That set will have the correct split-position. 0587 uint newLeftNode = computeSetFromNodes(leftNode, rightLeftNode, left, rightLeft, splitBit); 0588 0589 return createSetFromNodes(newLeftNode, rightRightNode, nullptr, rightRight); 0590 } else { 0591 return createSetFromNodes(leftNode, rightNode, left, right); 0592 } 0593 } 0594 0595 uint SetRepositoryAlgorithms::set_union(uint firstNode, uint secondNode, const SetNodeData* first, 0596 const SetNodeData* second, uchar splitBit) 0597 { 0598 if (firstNode == secondNode) 0599 return firstNode; 0600 0601 uint firstStart = first->start(), secondEnd = second->end(); 0602 0603 if (firstStart >= secondEnd) 0604 return computeSetFromNodes(secondNode, firstNode, second, first, splitBit); 0605 0606 uint firstEnd = first->end(), secondStart = second->start(); 0607 0608 if (secondStart >= firstEnd) 0609 return computeSetFromNodes(firstNode, secondNode, first, second, splitBit); 0610 0611 //The ranges of first and second do intersect 0612 0613 uint newStart = firstStart < secondStart ? firstStart : secondStart; 0614 uint newEnd = firstEnd > secondEnd ? firstEnd : secondEnd; 0615 0616 //Compute the split-position for the resulting merged node 0617 uint splitPosition = splitPositionForRange(newStart, newEnd, splitBit); 0618 0619 //Since the ranges overlap, we can be sure that either first or second contain splitPosition. 0620 //The node that contains it, will also be split by it. 0621 0622 if (splitPosition > firstStart && splitPosition < firstEnd && splitPosition > secondStart && 0623 splitPosition < secondEnd) { 0624 //The split-position intersect with both first and second. Continue the union on both sides of the split-position, and merge it. 0625 0626 uint firstLeftNode = first->leftNode(); 0627 uint firstRightNode = first->rightNode(); 0628 uint secondLeftNode = second->leftNode(); 0629 uint secondRightNode = second->rightNode(); 0630 0631 const SetNodeData* firstLeft = repository.itemFromIndex(firstLeftNode); 0632 const SetNodeData* firstRight = repository.itemFromIndex(firstRightNode); 0633 const SetNodeData* secondLeft = repository.itemFromIndex(secondLeftNode); 0634 const SetNodeData* secondRight = repository.itemFromIndex(secondRightNode); 0635 0636 Q_ASSERT(splitPosition >= firstLeft->end() && splitPosition <= firstRight->start()); 0637 Q_ASSERT(splitPosition >= secondLeft->end() && splitPosition <= secondRight->start()); 0638 0639 return createSetFromNodes(set_union(firstLeftNode, secondLeftNode, firstLeft, secondLeft, splitBit), 0640 set_union(firstRightNode, secondRightNode, firstRight, secondRight, splitBit)); 0641 } else if (splitPosition > firstStart && splitPosition < firstEnd) { 0642 uint firstLeftNode = first->leftNode(); 0643 uint firstRightNode = first->rightNode(); 0644 0645 const SetNodeData* firstLeft = repository.itemFromIndex(firstLeftNode); 0646 const SetNodeData* firstRight = repository.itemFromIndex(firstRightNode); 0647 0648 Q_ASSERT(splitPosition >= firstLeft->end() && splitPosition <= firstRight->start()); 0649 0650 //splitPosition does not intersect second. That means that second is completely on one side of it. 0651 //So we only need to union that side of first with second. 0652 0653 if (secondEnd <= splitPosition) { 0654 return createSetFromNodes(set_union(firstLeftNode, secondNode, firstLeft, second, 0655 splitBit), firstRightNode, nullptr, firstRight); 0656 } else { 0657 Q_ASSERT(secondStart >= splitPosition); 0658 return createSetFromNodes(firstLeftNode, set_union(firstRightNode, secondNode, firstRight, second, 0659 splitBit), firstLeft); 0660 } 0661 } else if (splitPosition > secondStart && splitPosition < secondEnd) { 0662 uint secondLeftNode = second->leftNode(); 0663 uint secondRightNode = second->rightNode(); 0664 0665 const SetNodeData* secondLeft = repository.itemFromIndex(secondLeftNode); 0666 const SetNodeData* secondRight = repository.itemFromIndex(secondRightNode); 0667 0668 Q_ASSERT(splitPosition >= secondLeft->end() && splitPosition <= secondRight->start()); 0669 0670 if (firstEnd <= splitPosition) { 0671 return createSetFromNodes(set_union(secondLeftNode, firstNode, secondLeft, first, 0672 splitBit), secondRightNode, nullptr, secondRight); 0673 } else { 0674 Q_ASSERT(firstStart >= splitPosition); 0675 return createSetFromNodes(secondLeftNode, set_union(secondRightNode, firstNode, secondRight, first, 0676 splitBit), secondLeft); 0677 } 0678 } else { 0679 //We would have stopped earlier of first and second don't intersect 0680 ifDebug(uint test = repository.findIndex(SetNodeDataRequest(first, repository, setRepository)); qCDebug( 0681 LANGUAGE) << "found index:" << test; ) 0682 Q_ASSERT(0); 0683 return 0; 0684 } 0685 } 0686 0687 bool SetRepositoryAlgorithms::set_equals(const SetNodeData* lhs, const SetNodeData* rhs) 0688 { 0689 if (lhs->leftNode() != rhs->leftNode() || lhs->rightNode() != rhs->rightNode()) 0690 return false; 0691 else 0692 return true; 0693 } 0694 0695 uint SetRepositoryAlgorithms::set_intersect(uint firstNode, uint secondNode, const SetNodeData* first, 0696 const SetNodeData* second, uchar splitBit) 0697 { 0698 if (firstNode == secondNode) 0699 return firstNode; 0700 0701 if (first->start() >= second->end()) 0702 return 0; 0703 0704 if (second->start() >= first->end()) 0705 return 0; 0706 0707 //The ranges of first and second do intersect 0708 uint firstStart = first->start(), firstEnd = first->end(), secondStart = second->start(), secondEnd = second->end(); 0709 0710 uint newStart = firstStart < secondStart ? firstStart : secondStart; 0711 uint newEnd = firstEnd > secondEnd ? firstEnd : secondEnd; 0712 0713 //Compute the split-position for the resulting merged node 0714 uint splitPosition = splitPositionForRange(newStart, newEnd, splitBit); 0715 0716 //Since the ranges overlap, we can be sure that either first or second contain splitPosition. 0717 //The node that contains it, will also be split by it. 0718 0719 if (splitPosition > firstStart && splitPosition < firstEnd && splitPosition > secondStart && 0720 splitPosition < secondEnd) { 0721 //The split-position intersect with both first and second. Continue the intersection on both sides 0722 0723 uint firstLeftNode = first->leftNode(); 0724 uint firstRightNode = first->rightNode(); 0725 0726 uint secondLeftNode = second->leftNode(); 0727 uint secondRightNode = second->rightNode(); 0728 0729 const SetNodeData* firstLeft = repository.itemFromIndex(firstLeftNode); 0730 const SetNodeData* firstRight = repository.itemFromIndex(firstRightNode); 0731 const SetNodeData* secondLeft = repository.itemFromIndex(secondLeftNode); 0732 const SetNodeData* secondRight = repository.itemFromIndex(secondRightNode); 0733 0734 Q_ASSERT(splitPosition >= firstLeft->end() && splitPosition <= firstRight->start()); 0735 Q_ASSERT(splitPosition >= secondLeft->end() && splitPosition <= secondRight->start()); 0736 0737 uint newLeftNode = set_intersect(firstLeftNode, secondLeftNode, firstLeft, secondLeft, splitBit); 0738 uint newRightNode = set_intersect(firstRightNode, secondRightNode, firstRight, secondRight, splitBit); 0739 0740 if (newLeftNode && newRightNode) 0741 return createSetFromNodes(newLeftNode, newRightNode); 0742 else if (newLeftNode) 0743 return newLeftNode; 0744 else 0745 return newRightNode; 0746 } else if (splitPosition > firstStart && splitPosition < firstEnd) { 0747 uint firstLeftNode = first->leftNode(); 0748 uint firstRightNode = first->rightNode(); 0749 0750 const SetNodeData* firstLeft = repository.itemFromIndex(firstLeftNode); 0751 const SetNodeData* firstRight = repository.itemFromIndex(firstRightNode); 0752 0753 Q_ASSERT(splitPosition >= firstLeft->end() && splitPosition <= firstRight->start()); 0754 0755 //splitPosition does not intersect second. That means that second is completely on one side of it. 0756 //So we can completely ignore the other side of first. 0757 0758 if (secondEnd <= splitPosition) { 0759 return set_intersect(firstLeftNode, secondNode, firstLeft, second, splitBit); 0760 } else { 0761 Q_ASSERT(secondStart >= splitPosition); 0762 return set_intersect(firstRightNode, secondNode, firstRight, second, splitBit); 0763 } 0764 } else if (splitPosition > secondStart && splitPosition < secondEnd) { 0765 uint secondLeftNode = second->leftNode(); 0766 uint secondRightNode = second->rightNode(); 0767 0768 const SetNodeData* secondLeft = repository.itemFromIndex(secondLeftNode); 0769 const SetNodeData* secondRight = repository.itemFromIndex(secondRightNode); 0770 0771 Q_ASSERT(splitPosition >= secondLeft->end() && splitPosition <= secondRight->start()); 0772 0773 if (firstEnd <= splitPosition) { 0774 return set_intersect(secondLeftNode, firstNode, secondLeft, first, splitBit); 0775 } else { 0776 Q_ASSERT(firstStart >= splitPosition); 0777 return set_intersect(secondRightNode, firstNode, secondRight, first, splitBit); 0778 } 0779 } else { 0780 //We would have stopped earlier of first and second don't intersect 0781 Q_ASSERT(0); 0782 return 0; 0783 } 0784 Q_ASSERT(0); 0785 } 0786 0787 bool SetRepositoryAlgorithms::set_contains(const SetNodeData* node, Index index) 0788 { 0789 while (true) { 0790 if (node->start() > index || node->end() <= index) 0791 return false; 0792 0793 if (node->contiguous()) 0794 return true; 0795 0796 const SetNodeData* leftNode = nodeFromIndex(node->leftNode()); 0797 0798 if (index < leftNode->end()) 0799 node = leftNode; 0800 else { 0801 const SetNodeData* rightNode = nodeFromIndex(node->rightNode()); 0802 node = rightNode; 0803 } 0804 } 0805 0806 return false; 0807 } 0808 0809 uint SetRepositoryAlgorithms::set_subtract(uint firstNode, uint secondNode, const SetNodeData* first, 0810 const SetNodeData* second, uchar splitBit) 0811 { 0812 if (firstNode == secondNode) 0813 return 0; 0814 0815 if (first->start() >= second->end() || second->start() >= first->end()) 0816 return firstNode; 0817 0818 //The ranges of first and second do intersect 0819 uint firstStart = first->start(), firstEnd = first->end(), secondStart = second->start(), secondEnd = second->end(); 0820 0821 uint newStart = firstStart < secondStart ? firstStart : secondStart; 0822 uint newEnd = firstEnd > secondEnd ? firstEnd : secondEnd; 0823 0824 //Compute the split-position for the resulting merged node 0825 uint splitPosition = splitPositionForRange(newStart, newEnd, splitBit); 0826 0827 //Since the ranges overlap, we can be sure that either first or second contain splitPosition. 0828 //The node that contains it, will also be split by it. 0829 0830 if (splitPosition > firstStart && splitPosition < firstEnd && splitPosition > secondStart && 0831 splitPosition < secondEnd) { 0832 //The split-position intersect with both first and second. Continue the subtract on both sides of the split-position, and merge it. 0833 0834 uint firstLeftNode = first->leftNode(); 0835 uint firstRightNode = first->rightNode(); 0836 0837 uint secondLeftNode = second->leftNode(); 0838 uint secondRightNode = second->rightNode(); 0839 0840 const SetNodeData* firstLeft = repository.itemFromIndex(firstLeftNode); 0841 const SetNodeData* firstRight = repository.itemFromIndex(firstRightNode); 0842 const SetNodeData* secondLeft = repository.itemFromIndex(secondLeftNode); 0843 const SetNodeData* secondRight = repository.itemFromIndex(secondRightNode); 0844 0845 Q_ASSERT(splitPosition >= firstLeft->end() && splitPosition <= firstRight->start()); 0846 Q_ASSERT(splitPosition >= secondLeft->end() && splitPosition <= secondRight->start()); 0847 0848 uint newLeftNode = set_subtract(firstLeftNode, secondLeftNode, firstLeft, secondLeft, splitBit); 0849 uint newRightNode = set_subtract(firstRightNode, secondRightNode, firstRight, secondRight, splitBit); 0850 0851 if (newLeftNode && newRightNode) 0852 return createSetFromNodes(newLeftNode, newRightNode); 0853 else if (newLeftNode) 0854 return newLeftNode; 0855 else 0856 return newRightNode; 0857 } else if (splitPosition > firstStart && splitPosition < firstEnd) { 0858 // Q_ASSERT(splitPosition >= firstLeft->end() && splitPosition <= firstRight->start()); 0859 0860 uint firstLeftNode = first->leftNode(); 0861 uint firstRightNode = first->rightNode(); 0862 0863 const SetNodeData* firstLeft = repository.itemFromIndex(firstLeftNode); 0864 const SetNodeData* firstRight = repository.itemFromIndex(firstRightNode); 0865 0866 //splitPosition does not intersect second. That means that second is completely on one side of it. 0867 //So we only need to subtract that side of first with second. 0868 0869 uint newLeftNode = firstLeftNode, newRightNode = firstRightNode; 0870 0871 if (secondEnd <= splitPosition) { 0872 newLeftNode = set_subtract(firstLeftNode, secondNode, firstLeft, second, splitBit); 0873 } else { 0874 Q_ASSERT(secondStart >= splitPosition); 0875 newRightNode = set_subtract(firstRightNode, secondNode, firstRight, second, splitBit); 0876 } 0877 0878 if (newLeftNode && newRightNode) 0879 return createSetFromNodes(newLeftNode, newRightNode); 0880 else if (newLeftNode) 0881 return newLeftNode; 0882 else 0883 return newRightNode; 0884 } else if (splitPosition > secondStart && splitPosition < secondEnd) { 0885 uint secondLeftNode = second->leftNode(); 0886 uint secondRightNode = second->rightNode(); 0887 0888 const SetNodeData* secondLeft = repository.itemFromIndex(secondLeftNode); 0889 const SetNodeData* secondRight = repository.itemFromIndex(secondRightNode); 0890 0891 Q_ASSERT(splitPosition >= secondLeft->end() && splitPosition <= secondRight->start()); 0892 0893 if (firstEnd <= splitPosition) { 0894 return set_subtract(firstNode, secondLeftNode, first, secondLeft, splitBit); 0895 } else { 0896 Q_ASSERT(firstStart >= splitPosition); 0897 return set_subtract(firstNode, secondRightNode, first, secondRight, splitBit); 0898 } 0899 } else { 0900 //We would have stopped earlier of first and second don't intersect 0901 Q_ASSERT(0); 0902 return 0; 0903 } 0904 Q_ASSERT(0); 0905 } 0906 0907 Set BasicSetRepository::createSetFromIndices(const std::vector<Index>& indices) 0908 { 0909 QMutexLocker lock(m_mutex); 0910 0911 if (indices.empty()) 0912 return Set(); 0913 0914 SetRepositoryAlgorithms alg(m_dataRepository, this); 0915 0916 return Set(alg.setForIndices(indices.begin(), indices.end()), this); 0917 } 0918 0919 Set BasicSetRepository::createSet(Index i) 0920 { 0921 QMutexLocker lock(m_mutex); 0922 SetNodeData data(i, i + 1); 0923 0924 return Set(m_dataRepository.index(SetNodeDataRequest(&data, m_dataRepository, this)), this); 0925 } 0926 0927 Set BasicSetRepository::createSet(const std::set<Index>& indices) 0928 { 0929 if (indices.empty()) 0930 return Set(); 0931 0932 QMutexLocker lock(m_mutex); 0933 0934 std::vector<Index> indicesVector; 0935 indicesVector.reserve(indices.size()); 0936 0937 for (unsigned int index : indices) { 0938 indicesVector.push_back(index); 0939 } 0940 0941 return createSetFromIndices(indicesVector); 0942 } 0943 0944 BasicSetRepository::BasicSetRepository(const QString& name, QRecursiveMutex* mutex, 0945 KDevelop::ItemRepositoryRegistry* registry, bool delayedDeletion) 0946 : m_dataRepository(this, name, registry, mutex) 0947 , m_mutex(nullptr) 0948 , m_delayedDeletion(delayedDeletion) 0949 { 0950 m_mutex = m_dataRepository.mutex(); 0951 } 0952 0953 struct StatisticsVisitor 0954 { 0955 explicit StatisticsVisitor(const SetDataRepository& _rep) : nodeCount(0) 0956 , badSplitNodeCount(0) 0957 , zeroRefCountNodes(0) 0958 , rep(_rep) 0959 { 0960 } 0961 bool operator()(const SetNodeData* item) 0962 { 0963 if (item->m_refCount == 0) 0964 ++zeroRefCountNodes; 0965 ++nodeCount; 0966 uint split = splitPositionForRange(item->start(), item->end()); 0967 if (item->hasSlaves()) 0968 if (split < rep.itemFromIndex(item->leftNode())->end() || 0969 split > rep.itemFromIndex(item->rightNode())->start()) 0970 ++badSplitNodeCount; 0971 return true; 0972 } 0973 uint nodeCount; 0974 uint badSplitNodeCount; 0975 uint zeroRefCountNodes; 0976 const SetDataRepository& rep; 0977 }; 0978 0979 void BasicSetRepository::printStatistics() const 0980 { 0981 StatisticsVisitor stats(m_dataRepository); 0982 m_dataRepository.visitAllItems<StatisticsVisitor>(stats); 0983 qCDebug(LANGUAGE) << "count of nodes:" << stats.nodeCount << "count of nodes with bad split:" << 0984 stats.badSplitNodeCount << "count of nodes with zero reference-count:" << stats.zeroRefCountNodes; 0985 } 0986 0987 BasicSetRepository::~BasicSetRepository() = default; 0988 0989 void BasicSetRepository::itemRemovedFromSets(uint /*index*/) 0990 { 0991 } 0992 0993 void BasicSetRepository::itemAddedToSets(uint /*index*/) 0994 { 0995 } 0996 0997 ////////////Set convenience functions////////////////// 0998 0999 bool Set::contains(Index index) const 1000 { 1001 if (!m_tree || !m_repository) 1002 return false; 1003 1004 QMutexLocker lock(m_repository->m_mutex); 1005 1006 SetRepositoryAlgorithms alg(m_repository->m_dataRepository, m_repository); 1007 return alg.set_contains(m_repository->m_dataRepository.itemFromIndex(m_tree), index); 1008 } 1009 1010 Set Set::operator +(const Set& first) const 1011 { 1012 if (!first.m_tree) 1013 return *this; 1014 else if (!m_tree || !m_repository) 1015 return first; 1016 1017 Q_ASSERT(m_repository == first.m_repository); 1018 1019 QMutexLocker lock(m_repository->m_mutex); 1020 1021 SetRepositoryAlgorithms alg(m_repository->m_dataRepository, m_repository); 1022 1023 uint retNode = alg.set_union(m_tree, first.m_tree, m_repository->m_dataRepository.itemFromIndex( 1024 m_tree), m_repository->m_dataRepository.itemFromIndex(first.m_tree)); 1025 1026 ifDebug(alg.check(retNode)); 1027 1028 return Set(retNode, m_repository); 1029 } 1030 1031 Set& Set::operator +=(const Set& first) 1032 { 1033 if (!first.m_tree) 1034 return *this; 1035 else if (!m_tree || !m_repository) { 1036 m_tree = first.m_tree; 1037 m_repository = first.m_repository; 1038 return *this; 1039 } 1040 1041 QMutexLocker lock(m_repository->m_mutex); 1042 1043 SetRepositoryAlgorithms alg(m_repository->m_dataRepository, m_repository); 1044 1045 m_tree = alg.set_union(m_tree, first.m_tree, m_repository->m_dataRepository.itemFromIndex( 1046 m_tree), m_repository->m_dataRepository.itemFromIndex(first.m_tree)); 1047 1048 ifDebug(alg.check(m_tree)); 1049 return *this; 1050 } 1051 1052 Set Set::operator &(const Set& first) const 1053 { 1054 if (!first.m_tree || !m_tree) 1055 return Set(); 1056 1057 Q_ASSERT(m_repository); 1058 1059 QMutexLocker lock(m_repository->m_mutex); 1060 1061 SetRepositoryAlgorithms alg(m_repository->m_dataRepository, m_repository); 1062 1063 Set ret(alg.set_intersect(m_tree, first.m_tree, m_repository->m_dataRepository.itemFromIndex( 1064 m_tree), m_repository->m_dataRepository.itemFromIndex(first.m_tree)), m_repository); 1065 1066 ifDebug(alg.check(ret.m_tree)); 1067 1068 return ret; 1069 } 1070 1071 Set& Set::operator &=(const Set& first) 1072 { 1073 if (!first.m_tree || !m_tree) { 1074 m_tree = 0; 1075 return *this; 1076 } 1077 1078 Q_ASSERT(m_repository); 1079 1080 QMutexLocker lock(m_repository->m_mutex); 1081 1082 SetRepositoryAlgorithms alg(m_repository->m_dataRepository, m_repository); 1083 1084 m_tree = alg.set_intersect(m_tree, first.m_tree, m_repository->m_dataRepository.itemFromIndex( 1085 m_tree), m_repository->m_dataRepository.itemFromIndex(first.m_tree)); 1086 ifDebug(alg.check(m_tree)); 1087 return *this; 1088 } 1089 1090 Set Set::operator -(const Set& rhs) const 1091 { 1092 if (!m_tree || !rhs.m_tree) 1093 return *this; 1094 1095 Q_ASSERT(m_repository); 1096 1097 QMutexLocker lock(m_repository->m_mutex); 1098 1099 SetRepositoryAlgorithms alg(m_repository->m_dataRepository, m_repository); 1100 1101 Set ret(alg.set_subtract(m_tree, rhs.m_tree, m_repository->m_dataRepository.itemFromIndex( 1102 m_tree), m_repository->m_dataRepository.itemFromIndex(rhs.m_tree)), m_repository); 1103 ifDebug(alg.check(ret.m_tree)); 1104 return ret; 1105 } 1106 1107 Set& Set::operator -=(const Set& rhs) 1108 { 1109 if (!m_tree || !rhs.m_tree) 1110 return *this; 1111 1112 Q_ASSERT(m_repository); 1113 1114 QMutexLocker lock(m_repository->m_mutex); 1115 1116 SetRepositoryAlgorithms alg(m_repository->m_dataRepository, m_repository); 1117 1118 m_tree = alg.set_subtract(m_tree, rhs.m_tree, m_repository->m_dataRepository.itemFromIndex( 1119 m_tree), m_repository->m_dataRepository.itemFromIndex(rhs.m_tree)); 1120 1121 ifDebug(alg.check(m_tree)); 1122 return *this; 1123 } 1124 1125 BasicSetRepository* Set::repository() const 1126 { 1127 return m_repository; 1128 } 1129 1130 void Set::staticRef() 1131 { 1132 if (!m_tree) 1133 return; 1134 1135 QMutexLocker lock(m_repository->m_mutex); 1136 SetNodeData* data = m_repository->m_dataRepository.dynamicItemFromIndexSimple(m_tree); 1137 ++data->m_refCount; 1138 } 1139 1140 ///Mutex must be locked 1141 void Set::unrefNode(uint current) 1142 { 1143 SetNodeData* data = m_repository->m_dataRepository.dynamicItemFromIndexSimple(current); 1144 Q_ASSERT(data->m_refCount); 1145 --data->m_refCount; 1146 if (!m_repository->delayedDeletion()) { 1147 if (data->m_refCount == 0) { 1148 if (data->leftNode()) { 1149 Q_ASSERT(data->rightNode()); 1150 unrefNode(data->rightNode()); 1151 unrefNode(data->leftNode()); 1152 } else { 1153 //Deleting a leaf 1154 Q_ASSERT(data->end() - data->start() == 1); 1155 m_repository->itemRemovedFromSets(data->start()); 1156 } 1157 1158 m_repository->m_dataRepository.deleteItem(current); 1159 } 1160 } 1161 } 1162 1163 ///Decrease the static reference-count of this set by one. This set must have a reference-count > 1. 1164 ///If this set reaches the reference-count zero, it will be deleted, and all sub-nodes that also reach the reference-count zero 1165 ///will be deleted as well. @warning Either protect ALL your sets by using reference-counting, or don't use it at all. 1166 void Set::staticUnref() 1167 { 1168 if (!m_tree) 1169 return; 1170 1171 QMutexLocker lock(m_repository->m_mutex); 1172 1173 unrefNode(m_tree); 1174 } 1175 1176 StringSetRepository::StringSetRepository(const QString& name, QRecursiveMutex* mutex) 1177 : Utils::BasicSetRepository(name, mutex) 1178 { 1179 } 1180 1181 void StringSetRepository::itemRemovedFromSets(uint index) 1182 { 1183 ///Call the IndexedString destructor with enabled reference-counting 1184 KDevelop::IndexedString string = KDevelop::IndexedString::fromIndex(index); 1185 1186 const KDevelop::DUChainReferenceCountingEnabler rcEnabler(&string, sizeof(KDevelop::IndexedString)); 1187 string.~IndexedString(); //Call destructor with enabled reference-counting 1188 } 1189 1190 void StringSetRepository::itemAddedToSets(uint index) 1191 { 1192 ///Call the IndexedString constructor with enabled reference-counting 1193 1194 KDevelop::IndexedString string = KDevelop::IndexedString::fromIndex(index); 1195 1196 char data[sizeof(KDevelop::IndexedString)] = {}; 1197 1198 const KDevelop::DUChainReferenceCountingEnabler rcEnabler(data, sizeof(KDevelop::IndexedString)); 1199 new (data) KDevelop::IndexedString(string); //Call constructor with enabled reference-counting 1200 } 1201 }