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 }