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

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 EMBEDDED_FREE_TREE
0008 #define EMBEDDED_FREE_TREE
0009 
0010 #include "kdevvarlengtharray.h"
0011 
0012 #include <QPair>
0013 
0014 #include <cstdlib>
0015 #include <iostream>
0016 #include <limits>
0017 
0018 //Uncomment this to search for tree-inconsistencies, however it's very expensive
0019 // #define DEBUG_FREEITEM_COUNT debugFreeItemCount(); verifyTreeConsistent(*m_centralFreeItem, 0, m_itemCount);
0020 #define DEBUG_FREEITEM_COUNT
0021 
0022 /**
0023  * This file implements algorithms that allow managing a sorted list of items, and managing "free" items
0024  * for reuse efficiently in that list. Among those free items a tree is built, and they are traversed
0025  * on insertion/removal to manage free items in the tree.
0026  *
0027  * There is specific needs on the embedded items:
0028  * - They must be markable "invalid", so after they are deleted they can stay in their place as invalid items.
0029  * - While they are invalid, they still must be able to hold 2 integers, needed for managing the tree of free items.
0030  * - One integer is needed for each list to hold a pointer to the central free item.
0031  *
0032  * Only these functions must be used to manipulate the lists, from the beginning up. First create an empty list
0033  * and initialize centralFreeItem with -1, and then you start adding items.
0034  *
0035  * Since the list is sorted, and each item can be contained only once, these lists actually represent a set.
0036  *
0037  * EmbeddedTreeAlgorithms implements an efficient "contains" function that uses binary search within the list.
0038  */
0039 
0040 namespace KDevelop {
0041 ///Responsible for handling the items in the list
0042 ///This is an example. ItemHandler::rightChild(..) and ItemHandler::leftChild(..) must be values that must be able to hold the count of positive
0043 ///values that will be the maximum size of the list, and additionally -1.
0044 //     template<class Data>
0045 //     class ExampleItemHandler {
0046 //         public:
0047 //         ExampleItemHandler(const Data& data) : m_data(data) {
0048 //         }
0049 //         int ItemHandler::rightChild() const {
0050 //             Q_ASSERT(0);
0051 //         }
0052 //         int ItemHandler::leftChild() const {
0053 //             Q_ASSERT(0);
0054 //         }
0055 //         void ItemHandler::setLeftChild(int child) {
0056 //             Q_ASSERT(0);
0057 //         }
0058 //         void setRightChild(int child) {
0059 //             Q_ASSERT(0);
0060 //         }
0061 //         bool operator<(const StandardItemHandler& rhs) const {
0062 //             Q_ASSERT(0);
0063 //         }
0064 //         //Copies this item into the given one
0065 //         void copyTo(Data& data) const {
0066 //             data = m_data;
0067 //         }
0068 //
0069 //         static void createFreeItem(Data& data) {
0070 //             data = Data();
0071 //         }
0072 //
0073 //         bool isFree() const {
0074 //             Q_ASSERT(0);
0075 //         }
0076 //
0077 //         const Data& data() {
0078 //         }
0079 //
0080 //         private:
0081 //             const Data& m_data;
0082 //     };
0083 
0084 /**
0085  * Use this for several constant algorithms on sorted lists with free-trees
0086  * */
0087 template<class Data, class ItemHandler>
0088 class EmbeddedTreeAlgorithms
0089 {
0090 
0091 public:
0092 
0093     EmbeddedTreeAlgorithms(const Data* items, uint itemCount, const int& centralFreeItem) : m_items(items)
0094         , m_itemCount(itemCount)
0095         , m_centralFreeItem(&centralFreeItem)
0096     {
0097     }
0098     ~EmbeddedTreeAlgorithms()
0099     {
0100     }
0101 
0102     ///Efficiently checks whether the item is contained in the set.
0103     ///If it is contained, returns the index. Else, returns -1.
0104 
0105     int indexOf(const Data& data)
0106     {
0107         return indexOf(data, 0, m_itemCount);
0108     }
0109 
0110     ///Searches the given item within the specified bounds.
0111     int indexOf(const Data& data, uint start, uint end)
0112     {
0113         while (1) {
0114             if (start >= end)
0115                 return -1;
0116 
0117             int center = (start + end) / 2;
0118 
0119             //Skip free items, since they cannot be used for ordering
0120             for (; center < ( int )end;) {
0121                 if (!ItemHandler::isFree(m_items[center]))
0122                     break;
0123                 ++center;
0124             }
0125 
0126             if (center == ( int )end) {
0127                 end = (start + end) / 2;       //No non-free items found in second half, so continue search in the other
0128             } else {
0129                 if (ItemHandler::equals(data, m_items[center])) {
0130                     return center;
0131                 } else if (data < m_items[center]) {
0132                     end = (start + end) / 2;
0133                 } else {
0134                     //Continue search in second half
0135                     start = center + 1;
0136                 }
0137             }
0138         }
0139     }
0140 
0141     ///Returns the first valid index that has a data-value larger or equal to @p data.
0142     ///Returns -1 if nothing is found.
0143     int lowerBound(const Data& data, int start, int end)
0144     {
0145         int currentBound = -1;
0146         while (1) {
0147             if (start >= end)
0148                 return currentBound;
0149 
0150             int center = (start + end) / 2;
0151 
0152             //Skip free items, since they cannot be used for ordering
0153             for (; center < end;) {
0154                 if (!ItemHandler::isFree(m_items[center]))
0155                     break;
0156                 ++center;
0157             }
0158 
0159             if (center == end) {
0160                 end = (start + end) / 2;       //No non-free items found in second half, so continue search in the other
0161             } else {
0162                 if (ItemHandler::equals(data, m_items[center])) {
0163                     return center;
0164                 } else if (data < m_items[center]) {
0165                     currentBound = center;
0166                     end = (start + end) / 2;
0167                 } else {
0168                     //Continue search in second half
0169                     start = center + 1;
0170                 }
0171             }
0172         }
0173     }
0174 
0175     uint countFreeItems() const
0176     {
0177         return countFreeItemsInternal(*m_centralFreeItem);
0178     }
0179     uint countFreeItemsNaive() const
0180     {
0181         uint ret = 0;
0182         for (uint a = 0; a < m_itemCount; ++a) {
0183             if (ItemHandler::isFree(m_items[a]))
0184                 ++ret;
0185         }
0186 
0187         return ret;
0188     }
0189 
0190     void verifyOrder()
0191     {
0192         Data last;
0193 
0194         for (uint a = 0; a < m_itemCount; ++a) {
0195             if (!ItemHandler::isFree(m_items[a])) {
0196                 if (!ItemHandler::isFree(last))
0197                     Q_ASSERT(last < m_items[a]);
0198                 last = m_items[a];
0199             }
0200         }
0201     }
0202 
0203     void verifyTreeConsistent()
0204     {
0205         verifyTreeConsistentInternal(*m_centralFreeItem, 0, m_itemCount);
0206         Q_ASSERT(countFreeItems() == countFreeItemsNaive());
0207     }
0208 
0209 private:
0210     void verifyTreeConsistentInternal(int position, int lowerBound, int upperBound)
0211     {
0212         if (position == -1)
0213             return;
0214         Q_ASSERT(lowerBound <= position && position < upperBound);
0215         verifyTreeConsistentInternal(ItemHandler::leftChild(m_items[position]), lowerBound, position);
0216         verifyTreeConsistentInternal(ItemHandler::rightChild(m_items[position]), position + 1, upperBound);
0217     }
0218 
0219     uint countFreeItemsInternal(int item) const
0220     {
0221         if (item == -1)
0222             return 0;
0223 
0224         return 1 + countFreeItemsInternal(ItemHandler::leftChild(m_items[item])) + countFreeItemsInternal(ItemHandler::rightChild(
0225                                                                                                               m_items[
0226                                                                                                                   item]));
0227     }
0228 
0229     const Data* m_items;
0230     uint m_itemCount;
0231     const int* m_centralFreeItem;
0232 };
0233 
0234 /**Use this to add items.
0235  * The added item must not be in the set yet!
0236  * General usage:
0237  * - Construct the object
0238  * - Check if newItemCount() equals the previous item-count. If not, construct
0239  *   a new list as large as newItemCount, and call object.transferData to transfer the data
0240  *   into the new list. The new size must match the returned newItemCount.
0241  * - Either call object.apply(), or let it be called automatically by the destructor.
0242  * @tparam increaseFraction By what fraction the list is increased when it needs to. For example the size will be increased by 1/5 if it's 5.
0243  * @tparam rebuildIfInsertionMoreExpensive The structure is rebuilt completely when an insertion needs a moving around of more than rebuildIfInsertionMoreExpensive times
0244                                           the count of items needed to be moved in worst case in a fresh tree.
0245  *                                          After rebuilding the tree, the free space is evenly distributed, and thus insertions require much less moving.
0246  * */
0247 template<class Data, class ItemHandler, int increaseFraction = 5, int rebuildIfInsertionMoreExpensive = 20>
0248 class EmbeddedTreeAddItem
0249 {
0250 
0251 public:
0252 
0253     EmbeddedTreeAddItem(Data* items, uint itemCount, int& centralFreeItem, const Data& add) : m_add(add)
0254         , m_items(items)
0255         , m_itemCount(itemCount)
0256         , m_centralFreeItem(&centralFreeItem)
0257         , m_applied(false)
0258         , m_needResize(false)
0259     {
0260         m_needResize = !apply();
0261     }
0262     ~EmbeddedTreeAddItem()
0263     {
0264         if (!m_applied)
0265             apply(true);
0266     }
0267 
0268     ///Check this to see whether a new item-count is needed. If this does not equal the given itemCount, then
0269     ///the data needs to be transferred into a new list using transferData
0270     uint newItemCount() const
0271     {
0272         if (!m_applied) {
0273             if (*m_centralFreeItem == -1) {
0274                 uint realItemCount = m_itemCount - countFreeItems(*m_centralFreeItem);
0275                 uint newItemCount = realItemCount + (realItemCount / increaseFraction);
0276                 if (newItemCount <= m_itemCount)
0277                     newItemCount = m_itemCount + 1;
0278 
0279                 return newItemCount;
0280             } else if (m_needResize) {
0281                 uint realItemCount = m_itemCount - countFreeItems(*m_centralFreeItem);
0282                 uint newItemCount = realItemCount + (realItemCount / increaseFraction);
0283 
0284                 return newItemCount;
0285             }
0286         }
0287         return m_itemCount;
0288     }
0289 
0290     ///Transfers the data into a new item-list. The size of the new item-list must equal newItemCount()
0291     void transferData(Data* newItems, uint newCount, int* newCentralFree = nullptr)
0292     {
0293         DEBUG_FREEITEM_COUNT
0294 
0295         uint currentRealCount = m_itemCount - countFreeItems(*m_centralFreeItem);
0296 //                 Q_ASSERT(currentRealCount + (currentRealCount/increaseFraction) == newCount);
0297 
0298         //Create a new list where the items from m_items are put into newItems, with the free items evenly
0299         //distributed, and a clean balanced free-tree.
0300         uint newFreeCount = newCount - currentRealCount;
0301         uint freeItemRaster;
0302         if (newFreeCount)
0303             freeItemRaster = newCount / newFreeCount;
0304         else {
0305             freeItemRaster = newCount + 1;       //No free items
0306         }
0307 
0308         ///@todo Do not iterate through all items, instead use the free-tree and memcpy for the ranges between free items.
0309         ///Ideally, even the free-tree would be built on-the-fly.
0310         Q_ASSERT(freeItemRaster);
0311         uint offset = 0;
0312         uint insertedValidCount = 0;
0313         for (uint a = 0; a < newCount; ++a) {
0314             //Create new free items at the end of their raster range
0315             if (a % freeItemRaster == (freeItemRaster - 1)) {
0316                 //We need to insert a free item
0317                 ItemHandler::createFreeItem(newItems[a]);
0318                 ++offset;
0319             } else {
0320                 ++insertedValidCount;
0321                 while (ItemHandler::isFree(m_items[a - offset]) && a - offset < m_itemCount)
0322                     --offset;
0323                 Q_ASSERT(a - offset < m_itemCount);
0324                 newItems[a] = m_items[a - offset];
0325 //                         Q_ASSERT(!ItemHandler::isFree(newItems[a]));
0326             }
0327         }
0328 
0329         Q_ASSERT(insertedValidCount == m_itemCount - countFreeItems(*m_centralFreeItem));
0330 //                  qCDebug(UTIL) << m_itemCount << newCount << offset;
0331 //                 Q_ASSERT(m_itemCount == newCount-offset);
0332 
0333         m_items = newItems;
0334         m_itemCount = newCount;
0335 
0336         if (newCentralFree)
0337             m_centralFreeItem  = newCentralFree;
0338 
0339         *m_centralFreeItem = buildFreeTree(newFreeCount, freeItemRaster, freeItemRaster - 1);
0340 
0341 //                 qCDebug(UTIL) << "count of new free items:" << newFreeCount;
0342 
0343 //                 Q_ASSERT(countFreeItems( *m_centralFreeItem ) == newFreeCount);
0344 
0345         DEBUG_FREEITEM_COUNT
0346     }
0347 
0348     ///Tries to put the item into the list. If the insertion would be too inefficient or is not possible, returns false, unless @param force is true
0349     bool apply(bool force = false)
0350     {
0351         if (m_applied)
0352             return true;
0353 
0354         if (*m_centralFreeItem == -1) {
0355             Q_ASSERT(!force);
0356             return false;
0357         }
0358 
0359         //Find the free item that is nearest to the target position in the item order
0360         int previousItem = -1;
0361         int currentItem = *m_centralFreeItem;
0362         int replaceCurrentWith = -1;
0363 
0364         //In currentLowerBound and currentUpperBound, we count the smallest contiguous range between free
0365         //items that the added items needs to be sorted into. If the range is empty, the item can just be inserted.
0366         int currentLowerBound = 0;
0367         int currentUpperBound = m_itemCount;
0368 
0369         //Now go down the chain, always into the items direction
0370 
0371         while (1) {
0372             QPair<int, int> freeBounds = leftAndRightRealItems(currentItem);
0373             const Data& current(m_items[currentItem]);
0374             if (freeBounds.first != -1 && m_add < m_items[freeBounds.first]) {
0375                 //Follow left child
0376                 currentUpperBound = freeBounds.first + 1;
0377 
0378                 if (ItemHandler::leftChild(current) != -1) {
0379                     //Continue traversing
0380                     previousItem = currentItem;
0381                     currentItem = ItemHandler::leftChild(current);
0382                 } else {
0383                     replaceCurrentWith = ItemHandler::rightChild(current);
0384                     break;
0385                 }
0386             } else if (freeBounds.second != -1 && m_items[freeBounds.second] < m_add) {
0387                 //Follow right child
0388                 currentLowerBound = freeBounds.second;
0389 
0390                 if (ItemHandler::rightChild(current) != -1) {
0391                     //Continue traversing
0392                     previousItem = currentItem;
0393                     currentItem = ItemHandler::rightChild(current);
0394                 } else {
0395                     replaceCurrentWith = ItemHandler::leftChild(current);
0396                     break;
0397                 }
0398             } else {
0399                 //We will use this item! So find a replacement for it in the tree, and update the structure
0400                 force = true;
0401                 currentLowerBound = currentUpperBound = currentItem;
0402 
0403                 int leftReplaceCandidate = -1, rightReplaceCandidate = -1;
0404                 if (ItemHandler::leftChild(current) != -1)
0405                     leftReplaceCandidate = rightMostChild(ItemHandler::leftChild(current));
0406                 if (ItemHandler::rightChild(current) != -1)
0407                     rightReplaceCandidate = leftMostChild(ItemHandler::rightChild(current));
0408 
0409                 ///@todo it's probably better using lowerBound and upperBound like in the "remove" version
0410                 //Left and right bounds of all children of current
0411                 int leftChildBound = leftMostChild(currentItem), rightChildBound = rightMostChild(currentItem);
0412                 Q_ASSERT(leftChildBound != -1 && rightChildBound != -1);
0413                 int childCenter = (leftChildBound + rightChildBound) / 2;
0414 
0415                 if (leftReplaceCandidate == -1 && rightReplaceCandidate == -1) {
0416                     //We don't have a replace candidate, since there is no children
0417                     Q_ASSERT(ItemHandler::leftChild(current) == -1);
0418                     Q_ASSERT(ItemHandler::rightChild(current) == -1);
0419                 } else if (rightReplaceCandidate == -1 ||
0420                            abs(leftReplaceCandidate - childCenter) < abs(rightReplaceCandidate - childCenter)) {
0421                     //pick the left replacement, since it's more central
0422                     Q_ASSERT(leftReplaceCandidate != -1);
0423                     replaceCurrentWith = leftReplaceCandidate;
0424 
0425                     Data& replaceWith(m_items[replaceCurrentWith]);
0426 
0427                     if (replaceCurrentWith == ItemHandler::leftChild(current)) {
0428                         //The left child of replaceWith can just stay as it is, and we just need to add the right child
0429                         Q_ASSERT(ItemHandler::rightChild(replaceWith) == -1);
0430                     } else {
0431                         takeRightMostChild(ItemHandler::leftChild(current));
0432 
0433                         //Since we'll be clearing the item, we have to put this childsomewhere else.
0434                         // Either make it our new "left" child, or make it the new left children "rightmost" child.
0435                         int addRightMostLeftChild = ItemHandler::leftChild(replaceWith);
0436 
0437                         ItemHandler::setLeftChild(replaceWith, -1);
0438 
0439                         Q_ASSERT(ItemHandler::leftChild(replaceWith) == -1);
0440                         Q_ASSERT(ItemHandler::rightChild(replaceWith) == -1);
0441 
0442                         if (ItemHandler::leftChild(current) != -1) {
0443                             Q_ASSERT(rightMostChild(ItemHandler::leftChild(current)) != replaceCurrentWith);
0444                             Q_ASSERT(ItemHandler::leftChild(current) == -1 || ItemHandler::leftChild(
0445                                          current) < replaceCurrentWith);
0446                             ItemHandler::setLeftChild(replaceWith, ItemHandler::leftChild(current));
0447 
0448                             if (addRightMostLeftChild != -1) {
0449                                 int rightMostLeft = rightMostChild(ItemHandler::leftChild(replaceWith));
0450                                 Q_ASSERT(rightMostLeft != -1);
0451 //                                     Q_ASSERT(item(rightMostLeft).ItemHandler::rightChild() == -1);
0452                                 Q_ASSERT(rightMostLeft < addRightMostLeftChild);
0453                                 ItemHandler::setRightChild(m_items[rightMostLeft], addRightMostLeftChild);
0454                             }
0455                         } else {
0456                             Q_ASSERT(addRightMostLeftChild == -1 || addRightMostLeftChild < replaceCurrentWith);
0457                             ItemHandler::setLeftChild(replaceWith, addRightMostLeftChild);
0458                         }
0459                     }
0460 
0461                     Q_ASSERT(ItemHandler::rightChild(current) == -1 ||
0462                              replaceCurrentWith < ItemHandler::rightChild(current));
0463                     ItemHandler::setRightChild(replaceWith, ItemHandler::rightChild(current));
0464                 } else {
0465                     //pick the right replacement, since it's more central
0466                     Q_ASSERT(rightReplaceCandidate != -1);
0467                     replaceCurrentWith = rightReplaceCandidate;
0468 
0469                     Data& replaceWith(m_items[replaceCurrentWith]);
0470 
0471                     if (replaceCurrentWith == ItemHandler::rightChild(current)) {
0472                         //The right child of replaceWith can just stay as it is, and we just need to add the left child
0473                         Q_ASSERT(ItemHandler::leftChild(replaceWith) == -1);
0474                     } else {
0475                         takeLeftMostChild(ItemHandler::rightChild(current));
0476 
0477                         //Since we'll be clearing the item, we have to put this childsomewhere else.
0478                         // Either make it our new "right" child, or make it the new right children "leftmost" child.
0479                         int addLeftMostRightChild = ItemHandler::rightChild(replaceWith);
0480 
0481                         ItemHandler::setRightChild(replaceWith, -1);
0482 
0483                         Q_ASSERT(ItemHandler::rightChild(replaceWith) == -1);
0484                         Q_ASSERT(ItemHandler::leftChild(replaceWith) == -1);
0485 
0486                         if (ItemHandler::rightChild(current) != -1) {
0487                             Q_ASSERT(leftMostChild(ItemHandler::rightChild(current)) != replaceCurrentWith);
0488                             Q_ASSERT(ItemHandler::rightChild(
0489                                          current) == -1 || replaceCurrentWith < ItemHandler::rightChild(current));
0490                             ItemHandler::setRightChild(replaceWith, ItemHandler::rightChild(current));
0491 
0492                             if (addLeftMostRightChild != -1) {
0493                                 int leftMostRight = leftMostChild(ItemHandler::rightChild(replaceWith));
0494                                 Q_ASSERT(leftMostRight != -1);
0495                                 Q_ASSERT(ItemHandler::leftChild(m_items[leftMostRight]) == -1);
0496                                 Q_ASSERT(addLeftMostRightChild < leftMostRight);
0497                                 ItemHandler::setLeftChild(m_items[leftMostRight], addLeftMostRightChild);
0498                             }
0499                         } else {
0500                             Q_ASSERT(addLeftMostRightChild == -1 || replaceCurrentWith < addLeftMostRightChild);
0501                             ItemHandler::setRightChild(replaceWith, addLeftMostRightChild);
0502                         }
0503                     }
0504 
0505                     Q_ASSERT(ItemHandler::leftChild(current) == -1 || ItemHandler::leftChild(
0506                                  current) < replaceCurrentWith);
0507                     ItemHandler::setLeftChild(replaceWith, ItemHandler::leftChild(current));
0508                 }
0509                 break;
0510             }
0511         }
0512 
0513         //We can insert now
0514         //currentItem and previousItem are the two items that best enclose the target item
0515 
0516 //                for(int a = currentLowerBound; a < currentUpperBound; ++a) {
0517 //                        Q_ASSERT(!ItemHandler::isFree(m_items[a]));
0518 //                }
0519 
0520         Q_ASSERT(currentItem < currentLowerBound || currentItem >= currentUpperBound);
0521 
0522         //If the current item is on a border of the bounds, it needs to be inserted in the right position.
0523         //Else, the current position already is right, and we only need to copy it in.
0524         if (currentLowerBound < currentUpperBound &&
0525             (currentItem == currentLowerBound - 1 || currentItem == currentUpperBound)) {
0526             if (!insertSorted(m_add, currentItem, currentLowerBound, currentUpperBound, force)) {
0527                 return false;
0528             }
0529         } else {
0530             ItemHandler::copyTo(m_add, m_items[currentItem]);
0531         }
0532 
0533         m_applied = true;
0534 
0535         //First, take currentItem out of the chain, by replacing it with current.rightChild in the parent
0536         if (previousItem != -1) {
0537             Data& previous(m_items[previousItem]);
0538             if (ItemHandler::leftChild(previous) == currentItem) {
0539                 Q_ASSERT(replaceCurrentWith == -1 || replaceCurrentWith < previousItem);
0540                 ItemHandler::setLeftChild(previous, replaceCurrentWith);
0541             } else if (ItemHandler::rightChild(previous) == currentItem) {
0542                 Q_ASSERT(replaceCurrentWith == -1 || previousItem < replaceCurrentWith);
0543                 ItemHandler::setRightChild(previous, replaceCurrentWith);
0544             } else {
0545                 Q_ASSERT(0);
0546             }
0547         } else {
0548             *m_centralFreeItem = replaceCurrentWith;
0549         }
0550 
0551         return true;
0552 
0553         DEBUG_FREEITEM_COUNT
0554     }
0555 
0556 private:
0557     void verifyTreeConsistent(int position, int lowerBound, int upperBound)
0558     {
0559         if (position == -1)
0560             return;
0561         Q_ASSERT(lowerBound <= position && position < upperBound);
0562         verifyTreeConsistent(ItemHandler::leftChild(m_items[position]), lowerBound, position);
0563         verifyTreeConsistent(ItemHandler::rightChild(m_items[position]), position + 1, upperBound);
0564     }
0565 
0566     void debugFreeItemCount()
0567     {
0568         uint count = 0;
0569         for (uint a = 0; a < m_itemCount; ++a) {
0570             if (isFree(m_items[a]))
0571                 ++count;
0572         }
0573 
0574         uint counted = countFreeItems(*m_centralFreeItem);
0575         Q_ASSERT(count == counted);
0576         Q_UNUSED(counted);
0577     }
0578 
0579     QPair<int, int> leftAndRightRealItems(int pos)
0580     {
0581         Q_ASSERT(ItemHandler::isFree(m_items[pos]));
0582         int left = -1, right = -1;
0583         for (int a = pos - 1; a >= 0; --a) {
0584             if (!ItemHandler::isFree(m_items[a])) {
0585                 left = a;
0586                 break;
0587             }
0588         }
0589 
0590         for (uint a = pos + 1; a < m_itemCount; ++a) {
0591             if (!ItemHandler::isFree(m_items[a])) {
0592                 right = a;
0593                 break;
0594             }
0595         }
0596 
0597         return qMakePair(left, right);
0598     }
0599 
0600     int buildFreeTree(int count, uint raster, int start)
0601     {
0602         Q_ASSERT((start % raster) == (raster - 1));
0603         Q_ASSERT(count != 0);
0604         Q_ASSERT(count <= ( int )m_itemCount);
0605         if (count == 1) {
0606             ItemHandler::createFreeItem(m_items[start]);
0607             return start;
0608         } else {
0609             int central = start + (count / 2) * raster;
0610             int leftCount = count / 2;
0611             int midCount = 1;
0612             int rightCount = count - leftCount - midCount;
0613             Q_ASSERT(leftCount + midCount <= count);
0614             ItemHandler::createFreeItem(m_items[central]);
0615             Q_ASSERT(ItemHandler::isFree(m_items[central]));
0616 
0617             int leftFreeTree = buildFreeTree(leftCount, raster, start);
0618             Q_ASSERT(leftFreeTree == -1 || leftFreeTree < central);
0619             ItemHandler::setLeftChild(m_items[central],  leftFreeTree);
0620 
0621             if (rightCount > 0) {
0622                 int rightFreeTree = buildFreeTree(rightCount, raster, central + raster);
0623                 Q_ASSERT(rightFreeTree == -1 || central < rightFreeTree);
0624                 ItemHandler::setRightChild(m_items[central], rightFreeTree);
0625             }
0626 
0627             return central;
0628         }
0629     }
0630 
0631     uint countFreeItems(int item) const
0632     {
0633         if (item == -1)
0634             return 0;
0635         const Data& current(m_items[item]);
0636 
0637         return 1 + countFreeItems(ItemHandler::leftChild(current)) + countFreeItems(ItemHandler::rightChild(current));
0638     }
0639 
0640     int leftMostChild(int pos) const
0641     {
0642         while (1) {
0643             if (ItemHandler::leftChild(m_items[pos]) != -1)
0644                 pos = ItemHandler::leftChild(m_items[pos]);
0645             else
0646                 return pos;
0647         }
0648     }
0649 
0650     int takeLeftMostChild(int pos) const
0651     {
0652         int parent = -1;
0653         while (1) {
0654             if (ItemHandler::leftChild(m_items[pos]) != -1) {
0655                 parent = pos;
0656                 pos = ItemHandler::leftChild(m_items[pos]);
0657             } else {
0658                 ItemHandler::setLeftChild(m_items[parent], -1);
0659                 return pos;
0660             }
0661         }
0662     }
0663 
0664     int rightMostChild(int pos) const
0665     {
0666         while (1) {
0667             if (ItemHandler::rightChild(m_items[pos]) != -1)
0668                 pos = ItemHandler::rightChild(m_items[pos]);
0669             else
0670                 return pos;
0671         }
0672     }
0673 
0674     int takeRightMostChild(int pos) const
0675     {
0676         int parent = -1;
0677         while (1) {
0678             if (ItemHandler::rightChild(m_items[pos]) != -1) {
0679                 parent = pos;
0680                 pos = ItemHandler::rightChild(m_items[pos]);
0681             } else {
0682                 ItemHandler::setRightChild(m_items[parent], -1);
0683                 return pos;
0684             }
0685         }
0686     }
0687 
0688     ///Maximum "moving" out of the way of items without forcing a complete rebuild of the list
0689     inline int maxMoveAround() const
0690     {
0691         return increaseFraction * rebuildIfInsertionMoreExpensive;
0692     }
0693 
0694     ///Inserts the given data item into position @p pos, and updates the sorting
0695     ///@param data can be another empty item, that together with @p pos represents the closest enclosure of the target position
0696     ///@return Whether the item could be inserted. It is not inserted if
0697     bool insertSorted(const Data& data, int pos, int start, int end, bool force)
0698     {
0699 
0700         if (pos < start)
0701             start = pos;
0702         if (pos >= end)
0703             end = pos + 1;
0704 
0705 /*               for(int a = start; a < end; ++a) {
0706                    if(a != pos) {
0707                        Q_ASSERT(!ItemHandler::isFree(m_items[a]));
0708                    }
0709                }*/
0710         EmbeddedTreeAlgorithms<Data, ItemHandler> alg(m_items, m_itemCount, *m_centralFreeItem);
0711         int bound = alg.lowerBound(data, start, end);
0712         //Now find the position that should be taken
0713         if (bound == -1)
0714             bound = end;
0715 
0716         //Now our item should end up right before bound
0717 
0718         int target;
0719         //bound cannot be pos, because pos is invalid
0720         Q_ASSERT(bound != pos);
0721 
0722 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 800)
0723 #pragma GCC diagnostic push
0724 #pragma GCC diagnostic ignored "-Wclass-memaccess"
0725 #endif
0726         //Shuffle around the item at the free pos, so reference counting in constructors/destructors is not screwed up
0727         char backup[sizeof(Data)];
0728         memcpy(backup, m_items + pos, sizeof(Data));
0729 
0730         if (bound < pos) {
0731             if (!force && pos - bound > maxMoveAround()) {
0732 //                         qCDebug(UTIL) << "increasing because" << pos-bound << ">" << maxMoveAround() << "left free items:" << countFreeItems(*m_centralFreeItem) << "target free items:" << (m_itemCount-countFreeItems(*m_centralFreeItem))/increaseFraction;
0733                 return false;
0734             }
0735             //Move [bound, pos) one to right, and insert at bound
0736             memmove(m_items + bound + 1, m_items + bound, sizeof(Data) * (pos - bound));
0737             target = bound;
0738         } else {
0739             Q_ASSERT(bound > pos);
0740             if (!force && bound - pos - 1 > maxMoveAround()) {
0741 //                         qCDebug(UTIL) << "increasing because" << bound-pos-1 << ">" << maxMoveAround() << "left free items:" << countFreeItems(*m_centralFreeItem)<< "target free items:" << (m_itemCount-countFreeItems(*m_centralFreeItem))/increaseFraction;
0742                 return false;
0743             }
0744             //Move (pos, bound) one to left, and insert at bound-1
0745             memmove(m_items + pos, m_items + pos + 1, sizeof(Data) * (bound - pos - 1));
0746             target = bound - 1;
0747         }
0748         memcpy(m_items + target, backup, sizeof(Data));
0749 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 800)
0750 #pragma GCC diagnostic pop
0751 #endif
0752 
0753         ItemHandler::copyTo(data, m_items[target]);
0754         return true;
0755     }
0756 
0757     Q_DISABLE_COPY(EmbeddedTreeAddItem)
0758 
0759 private:
0760     const Data& m_add;
0761     Data* m_items;
0762     uint m_itemCount;
0763     int* m_centralFreeItem;
0764     bool m_applied, m_needResize;
0765 };
0766 
0767 /**Use this to add items.
0768  * The removed item must be in the set!
0769  * General usage:
0770  * - Construct the object
0771  * - Check if newItemCount() equals the previous item-count. If not, construct
0772  *   a new list as large as newItemCount, and call object.transferData to transfer the data
0773  *   into the new list. The new size must match the returned newItemCount.
0774  * However this may also be ignored if the memory-saving is not wanted in that moment.
0775  * */
0776 template<class Data, class ItemHandler, int increaseFraction = 5>
0777 class EmbeddedTreeRemoveItem
0778 {
0779 
0780 public:
0781 
0782     EmbeddedTreeRemoveItem(Data* items, uint itemCount, int& centralFreeItem, const Data& remove) : m_remove(remove)
0783         , m_items(items)
0784         , m_itemCount(itemCount)
0785         , m_centralFreeItem(&centralFreeItem)
0786         , m_insertedAtDepth(0)
0787     {
0788         apply();
0789     }
0790 
0791     ~EmbeddedTreeRemoveItem()
0792     {
0793     }
0794 
0795     ///Check this to see whether a new item-count is needed. If this does not equal the given itemCount, then
0796     ///the data needs to be transferred into a new list using transferData
0797     uint newItemCount() const
0798     {
0799         uint maxFreeItems = ((m_itemCount / increaseFraction) * 3) / 2 + 1;
0800         //First we approximate the count of free items using the insertion depth
0801         if (m_insertedAtDepth >= 32 || (1u << m_insertedAtDepth) >= maxFreeItems) {
0802             uint freeCount = countFreeItems(*m_centralFreeItem);
0803             if (freeCount > maxFreeItems || freeCount == m_itemCount) {
0804                 return m_itemCount - freeCount;
0805             }
0806         }
0807 
0808         return m_itemCount;
0809     }
0810 
0811     ///Transfers the data into a new item-list. The size of the new item-list must equal newItemCount()
0812     void transferData(Data* newItems, uint newCount, int* newCentralFree = nullptr)
0813     {
0814         DEBUG_FREEITEM_COUNT
0815         //We only transfer into a new list when all the free items are used up
0816 
0817         //Create a list where only the non-free items exist
0818         uint offset = 0;
0819         for (uint a = 0; a < m_itemCount; ++a) {
0820             if (!ItemHandler::isFree(m_items[a])) {
0821                 newItems[offset] = m_items[a];
0822                 ++offset;
0823             }
0824         }
0825 
0826         Q_ASSERT(offset == newCount);
0827 
0828         if (newCentralFree)
0829             m_centralFreeItem = newCentralFree;
0830         *m_centralFreeItem = -1;
0831         m_items = newItems;
0832         m_itemCount = newCount;
0833         DEBUG_FREEITEM_COUNT
0834     }
0835 
0836 private:
0837     void verifyTreeConsistent(int position, int lowerBound, int upperBound)
0838     {
0839         if (position == -1)
0840             return;
0841         Q_ASSERT(lowerBound <= position && position < upperBound);
0842         verifyTreeConsistent(ItemHandler::leftChild(m_items[position]), lowerBound, position);
0843         verifyTreeConsistent(ItemHandler::rightChild(m_items[position]), position + 1, upperBound);
0844     }
0845 
0846     uint countFreeItems(int item) const
0847     {
0848         if (item == -1)
0849             return 0;
0850         const Data& current(m_items[item]);
0851 
0852         return 1 + countFreeItems(ItemHandler::leftChild(current)) + countFreeItems(ItemHandler::rightChild(current));
0853     }
0854 
0855     int findItem(const Data& data, uint start, uint end)
0856     {
0857         EmbeddedTreeAlgorithms<Data, ItemHandler> alg(m_items, m_itemCount, *m_centralFreeItem);
0858         return alg.indexOf(data, start, end);
0859     }
0860 
0861     void apply()
0862     {
0863         DEBUG_FREEITEM_COUNT
0864 
0865         int removeIndex = findItem(m_remove, 0, m_itemCount);
0866         Q_ASSERT(removeIndex != -1);
0867         Q_ASSERT(!ItemHandler::isFree(m_items[removeIndex]));
0868 
0869         //Find the free item that is nearest to the target position in the item order
0870         int currentItem = *m_centralFreeItem;
0871 
0872         int lowerBound = 0;        //The minimum position the searched item can have
0873         int upperBound = m_itemCount;        //The lowest known position the searched item can _not_ have
0874 
0875         if (*m_centralFreeItem == -1) {
0876             *m_centralFreeItem = removeIndex;
0877             Q_ASSERT(*m_centralFreeItem != -1);
0878             ItemHandler::createFreeItem(m_items[*m_centralFreeItem]);
0879             return;
0880         }
0881 
0882         //Now go down the chain, always into the items direction
0883         ///@todo make the structure better: Don't just put left/right child, but also swap when needed
0884         ///      to balance the tree
0885         while (1) {
0886             Q_ASSERT(removeIndex != currentItem);
0887             Data& current(m_items[currentItem]);
0888             ++m_insertedAtDepth;
0889             if (removeIndex < currentItem) {
0890                 upperBound = currentItem;
0891                 //Follow left child
0892                 if (ItemHandler::leftChild(current) != -1) {
0893                     //Continue traversing
0894                     currentItem = ItemHandler::leftChild(current);
0895                     Q_ASSERT(currentItem >= lowerBound && currentItem < upperBound);
0896                 } else {
0897                     //The to-be deleted item is before current, and can be added as left child to current
0898                     int item = findItem(m_remove, lowerBound, upperBound);
0899                     Q_ASSERT(item == removeIndex);
0900                     ItemHandler::createFreeItem(m_items[item]);
0901                     Q_ASSERT(item == -1 || item < currentItem);
0902                     ItemHandler::setLeftChild(current, item);
0903                     Q_ASSERT(item >= lowerBound && item < upperBound);
0904                     break;
0905                 }
0906             } else {
0907                 lowerBound = currentItem + 1;
0908                 //Follow right child
0909                 if (ItemHandler::rightChild(current) != -1) {
0910                     //Continue traversing
0911                     currentItem = ItemHandler::rightChild(current);
0912                     Q_ASSERT(currentItem >= lowerBound && currentItem < upperBound);
0913                 } else {
0914                     //The to-be deleted item is behind current, and can be added as right child to current
0915                     int item = findItem(m_remove, lowerBound, upperBound);
0916                     Q_ASSERT(item == removeIndex);
0917                     ItemHandler::createFreeItem(m_items[item]);
0918                     Q_ASSERT(item == -1 || currentItem < item);
0919                     ItemHandler::setRightChild(current, item);
0920                     Q_ASSERT(item >= lowerBound && item < upperBound);
0921                     break;
0922                 }
0923             }
0924         }
0925 
0926         DEBUG_FREEITEM_COUNT
0927     }
0928 
0929     void debugFreeItemCount()
0930     {
0931         uint count = 0;
0932         for (uint a = 0; a < m_itemCount; ++a) {
0933             if (ItemHandler::isFree(m_items[a]))
0934                 ++count;
0935         }
0936 
0937         uint counted = countFreeItems(*m_centralFreeItem);
0938         Q_ASSERT(count == counted);
0939         Q_UNUSED(counted);
0940     }
0941 
0942     const Data& m_remove;
0943     Data* m_items;
0944     uint m_itemCount;
0945     int* m_centralFreeItem;
0946     int m_insertedAtDepth;
0947 };
0948 }
0949 
0950 #endif