• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDevelop Platform Libraries
  • Sitemap
  • Contact Us
 

util

embeddedfreetree.h

00001 /* This file is part of KDevelop
00002     Copyright 2008 David Nolden <david.nolden.kdevelop@art-master.de>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #ifndef EMBEDDED_FREE_TREE
00020 #define EMBEDDED_FREE_TREE
00021 
00022 #include <sys/types.h>
00023 #include <limits>
00024 #include <stdlib.h>
00025 #include <QtCore/QPair>
00026 #include "kdevvarlengtharray.h"
00027 #include <iostream>
00028 
00029 //Uncomment this to search for tree-inconsistencies, however it's very expensive
00030 // #define DEBUG_FREEITEM_COUNT debugFreeItemCount(); verifyTreeConsistent(*m_centralFreeItem, 0, m_itemCount);
00031 #define DEBUG_FREEITEM_COUNT
00032 
00051 namespace KDevelop {
00055 //     template<class Data>
00056 //     class ExampleItemHandler {
00057 //         public:
00058 //         ExampleItemHandler(const Data& data) : m_data(data) {
00059 //         }
00060 //         int ItemHandler::rightChild() const {
00061 //             Q_ASSERT(0);
00062 //         }
00063 //         int ItemHandler::leftChild() const {
00064 //             Q_ASSERT(0);
00065 //         }
00066 //         void ItemHandler::setLeftChild(int child) {
00067 //             Q_ASSERT(0);
00068 //         }
00069 //         void setRightChild(int child) {
00070 //             Q_ASSERT(0);
00071 //         }
00072 //         bool operator<(const StandardItemHandler& rhs) const {
00073 //             Q_ASSERT(0);
00074 //         }
00075 //         //Copies this item into the given one
00076 //         void copyTo(Data& data) const {
00077 //             data = m_data;
00078 //         }
00079 //         
00080 //         static void createFreeItem(Data& data) {
00081 //             data = Data();
00082 //         }
00083 //         
00084 //         bool isFree() const {
00085 //             Q_ASSERT(0);
00086 //         }
00087 //
00088 //         const Data& data() {
00089 //         }
00090 //         
00091 //         private:
00092 //             const Data& m_data;
00093 //     };
00094 
00098     template<class Data, class ItemHandler>
00099     class EmbeddedTreeAlgorithms {
00100 
00101         public:
00102             
00103             EmbeddedTreeAlgorithms(const Data* items, uint itemCount, const int& centralFreeItem) : m_items(items), m_itemCount(itemCount), m_centralFreeItem(&centralFreeItem) {
00104             }
00105             ~EmbeddedTreeAlgorithms() {
00106             }
00107 
00110 
00111             int indexOf(const Data& data) {
00112                 return indexOf(data, 0, m_itemCount);
00113             }
00114 
00116             int indexOf(const Data& data, uint start, uint end) {
00117                 while(1) {
00118                     if(start >= end)
00119                         return -1;
00120                     
00121                     int center = (start + end)/2;
00122                     
00123                     //Skip free items, since they cannot be used for ordering
00124                     for(; center < (int)end; ) {
00125                         if(!ItemHandler::isFree(m_items[center]))
00126                             break;
00127                         ++center;
00128                     }
00129                     
00130                     if(center == (int)end) {
00131                         end = (start + end)/2; //No non-free items found in second half, so continue search in the other
00132                     }else{
00133                         if(ItemHandler::equals(data, m_items[center])) {
00134                             return center;
00135                         }else if(data < m_items[center]) {
00136                             end = (start + end)/2;
00137                         }else{
00138                             //Continue search in second half
00139                             start = center+1;
00140                         }
00141                     }
00142                 }
00143             }
00144 
00147             int lowerBound(const Data& data, int start, int end) {
00148                 int currentBound = -1;
00149                 while(1) {
00150                     if(start >= end)
00151                         return currentBound;
00152                     
00153                     int center = (start + end)/2;
00154                     
00155                     //Skip free items, since they cannot be used for ordering
00156                     for(; center < end; ) {
00157                         if(!ItemHandler::isFree(m_items[center]))
00158                             break;
00159                         ++center;
00160                     }
00161                     
00162                     if(center == end) {
00163                         end = (start + end)/2; //No non-free items found in second half, so continue search in the other
00164                     }else{
00165                         if(ItemHandler::equals(data, m_items[center])) {
00166                             return center;
00167                         }else if(data < m_items[center]) {
00168                             currentBound = center;
00169                             end = (start + end)/2;
00170                         }else{
00171                             //Continue search in second half
00172                             start = center+1;
00173                         }
00174                     }
00175                 }
00176             }
00177 
00178         uint countFreeItems() const {
00179             return countFreeItemsInternal(*m_centralFreeItem);
00180         }
00181         uint countFreeItemsNaive() const {
00182             uint ret = 0;
00183             for(uint a = 0; a < m_itemCount; ++a) {
00184                 if(ItemHandler::isFree(m_items[a]))
00185                     ++ret;
00186             }
00187             return ret;
00188         }
00189         
00190         void verifyOrder() {
00191             Data last;
00192             
00193             for(uint a = 0; a < m_itemCount; ++a) {
00194                 if(!ItemHandler::isFree(m_items[a])) {
00195                     if(!ItemHandler::isFree(last))
00196                         Q_ASSERT(last < m_items[a]);
00197                     last = m_items[a];
00198                 }
00199             }
00200         }
00201 
00202         void verifyTreeConsistent() {
00203             verifyTreeConsistentInternal(*m_centralFreeItem, 0, m_itemCount);
00204             Q_ASSERT(countFreeItems() == countFreeItemsNaive());
00205         }
00206         
00207         private:
00208         void verifyTreeConsistentInternal(int position, int lowerBound, int upperBound) {
00209             if(position == -1)
00210                 return;
00211             Q_ASSERT(lowerBound <= position && position < upperBound);
00212             verifyTreeConsistentInternal(ItemHandler::leftChild(m_items[position]), lowerBound, position);
00213             verifyTreeConsistentInternal(ItemHandler::rightChild(m_items[position]), position+1, upperBound);
00214         }
00215         
00216         uint countFreeItemsInternal(int item) const {
00217             if(item == -1)
00218                 return 0;
00219             
00220             return 1 + countFreeItemsInternal(ItemHandler::leftChild(m_items[item])) + countFreeItemsInternal(ItemHandler::rightChild(m_items[item]));
00221         }
00222 
00223            const Data* m_items;
00224            uint m_itemCount;
00225            const int* m_centralFreeItem;
00226     };
00227     
00241     template<class Data, class ItemHandler, int increaseFraction = 5, int rebuildIfInsertionMoreExpensive = 20>
00242     class EmbeddedTreeAddItem {
00243 
00244         public:
00245             
00246             EmbeddedTreeAddItem(Data* items, uint itemCount, int& centralFreeItem, const Data& add) : m_add(add), m_items(items), m_itemCount(itemCount), m_centralFreeItem(&centralFreeItem), m_applied(false), m_needResize(false) {
00247                 m_needResize = !apply();
00248             }
00249             ~EmbeddedTreeAddItem() {
00250                 if(!m_applied)
00251                     apply(true);
00252             }
00253 
00256             uint newItemCount() const {
00257                 if(!m_applied) {
00258                     if(*m_centralFreeItem == -1) {
00259                         uint realItemCount = m_itemCount - countFreeItems(*m_centralFreeItem);
00260                         uint newItemCount = realItemCount + (realItemCount/increaseFraction);
00261                         if(newItemCount <= m_itemCount)
00262                             newItemCount = m_itemCount+1;
00263                         
00264                         return newItemCount;
00265                     }else if(m_needResize) {
00266                         uint realItemCount = m_itemCount - countFreeItems(*m_centralFreeItem);
00267                         uint newItemCount = realItemCount + (realItemCount/increaseFraction);
00268                         
00269                         return newItemCount;
00270                     }
00271                 }
00272                 return m_itemCount;
00273             }
00274             
00276             void transferData(Data* newItems, uint newCount, int* newCentralFree = 0) {
00277                 DEBUG_FREEITEM_COUNT
00278                 
00279                 uint currentRealCount = m_itemCount - countFreeItems(*m_centralFreeItem);
00280 //                 Q_ASSERT(currentRealCount + (currentRealCount/increaseFraction) == newCount);
00281                 
00282                 //Create a new list where the items from m_items are put into newItems, with the free items evenly
00283                 //distributed, and a clean balanced free-tree.
00284                 uint newFreeCount = newCount - currentRealCount;
00285                 volatile uint freeItemRaster;
00286                 if(newFreeCount)
00287                     freeItemRaster = newCount / newFreeCount;
00288                 else {
00289                     freeItemRaster = newCount+1; //No free items
00290                 }
00291                     
00294                 Q_ASSERT(freeItemRaster);
00295                 uint offset = 0;
00296                 uint insertedValidCount = 0;
00297                 for(uint a = 0; a < newCount; ++a) {
00298                     //Create new free items at the end of their raster range
00299                     if(a % freeItemRaster == (freeItemRaster-1)) {
00300                         //We need to insert a free item
00301                         ItemHandler::createFreeItem(newItems[a]);
00302                         ++offset;
00303                     }else{
00304                         ++insertedValidCount;
00305                         while(ItemHandler::isFree(m_items[a-offset]) && a-offset < m_itemCount)
00306                             --offset;
00307                         Q_ASSERT(a-offset < m_itemCount);
00308                         newItems[a] = m_items[a-offset];
00309 //                         Q_ASSERT(!ItemHandler::isFree(newItems[a]));
00310                     }
00311                 }
00312                 Q_ASSERT(insertedValidCount == m_itemCount - countFreeItems(*m_centralFreeItem));
00313 //                  kDebug() << m_itemCount << newCount << offset;
00314 //                 Q_ASSERT(m_itemCount == newCount-offset);
00315                 
00316                 m_items = newItems;
00317                 m_itemCount = newCount;
00318                 
00319                 if(newCentralFree)
00320                     m_centralFreeItem  = newCentralFree;
00321 
00322                 *m_centralFreeItem = buildFreeTree(newFreeCount, freeItemRaster, freeItemRaster-1);
00323                
00324 //                 kDebug() << "count of new free items:" << newFreeCount;
00325                 
00326 //                 Q_ASSERT(countFreeItems( *m_centralFreeItem ) == newFreeCount);
00327                 
00328                 DEBUG_FREEITEM_COUNT
00329             }
00330             
00332            bool apply(bool force = false) {
00333                if(m_applied)
00334                    return true;
00335                
00336                if(*m_centralFreeItem == -1) {
00337                    Q_ASSERT(!force);
00338                    return false;
00339                }
00340                
00341                //Find the free item that is nearest to the target position in the item order
00342                int previousItem = -1;
00343                int currentItem = *m_centralFreeItem;
00344                int replaceCurrentWith = -1;
00345                
00346                //In currentLowerBound and currentUpperBound, we count the smallest contiguous range between free
00347                //items that the added items needs to be sorted into. If the range is empty, the item can just be inserted.
00348                int currentLowerBound = 0;
00349                int currentUpperBound = m_itemCount;
00350                
00351                //Now go down the chain, always into the items direction
00352                
00353                while(1) {
00354                    QPair<int, int> freeBounds = leftAndRightRealItems(currentItem);
00355                    const Data& current(m_items[currentItem]);
00356                    if(freeBounds.first != -1 && m_add < m_items[freeBounds.first]) {
00357                        //Follow left child
00358                        currentUpperBound = freeBounds.first+1;
00359                        
00360                        if(ItemHandler::leftChild(current) != -1) {
00361                            //Continue traversing
00362                            previousItem = currentItem;
00363                            currentItem = ItemHandler::leftChild(current);
00364                        }else{
00365                            replaceCurrentWith = ItemHandler::rightChild(current);
00366                            break;
00367                        }
00368                    }else if(freeBounds.second != -1 && m_items[freeBounds.second] < m_add) {
00369                        //Follow right child
00370                        currentLowerBound = freeBounds.second;
00371                        
00372                        if(ItemHandler::rightChild(current) != -1) {
00373                            //Continue traversing
00374                            previousItem = currentItem;
00375                            currentItem = ItemHandler::rightChild(current);
00376                        }else{
00377                            replaceCurrentWith = ItemHandler::leftChild(current);
00378                            break;
00379                        }
00380                    }else{
00381                        //We will use this item! So find a replacement for it in the tree, and update the structure
00382                        force = true;
00383                        currentLowerBound = currentUpperBound = currentItem;
00384                        
00385                        int leftReplaceCandidate = -1, rightReplaceCandidate = -1;
00386                        if(ItemHandler::leftChild(current) != -1)
00387                            leftReplaceCandidate = rightMostChild(ItemHandler::leftChild(current));
00388                        if(ItemHandler::rightChild(current) != -1)
00389                            rightReplaceCandidate = leftMostChild(ItemHandler::rightChild(current));
00390                        
00392                        //Left and right bounds of all children of current
00393                        int leftChildBound = leftMostChild(currentItem), rightChildBound = rightMostChild(currentItem);
00394                        Q_ASSERT(leftChildBound != -1 && rightChildBound != -1);
00395                        int childCenter = (leftChildBound + rightChildBound)/2;
00396                        
00397                        if(leftReplaceCandidate == -1 && rightReplaceCandidate == -1) {
00398                           //We don't have a replace candidate, since there is no children
00399                           Q_ASSERT(ItemHandler::leftChild(current) == -1);
00400                           Q_ASSERT(ItemHandler::rightChild(current) == -1);
00401                        }else if(rightReplaceCandidate == -1 || abs(leftReplaceCandidate - childCenter) < abs(rightReplaceCandidate - childCenter)) {
00402                            //pick the left replacement, since it's more central
00403                            Q_ASSERT(leftReplaceCandidate != -1);
00404                            replaceCurrentWith = leftReplaceCandidate;
00405                            
00406                            Data& replaceWith(m_items[replaceCurrentWith]);
00407                            
00408                            if(replaceCurrentWith == ItemHandler::leftChild(current)) {
00409                                //The left child of replaceWith can just stay as it is, and we just need to add the right child
00410                                Q_ASSERT(ItemHandler::rightChild(replaceWith) == -1);
00411                            }else{
00412                             takeRightMostChild(ItemHandler::leftChild(current));
00413                             
00414                             //Since we'll be clearing the item, we have to put this childsomewhere else. 
00415                             // Either make it our new "left" child, or make it the new left children "rightmost" child.
00416                             int addRightMostLeftChild = ItemHandler::leftChild(replaceWith);
00417                             
00418                             ItemHandler::setLeftChild(replaceWith, -1);
00419                             
00420                             Q_ASSERT(ItemHandler::leftChild(replaceWith) == -1);
00421                             Q_ASSERT(ItemHandler::rightChild(replaceWith) == -1);
00422                             
00423                             if(ItemHandler::leftChild(current) != -1)
00424                             {
00425                                 Q_ASSERT(rightMostChild(ItemHandler::leftChild(current)) != replaceCurrentWith);
00426                                 Q_ASSERT(ItemHandler::leftChild(current) == -1 || ItemHandler::leftChild(current) < replaceCurrentWith);
00427                                 ItemHandler::setLeftChild(replaceWith, ItemHandler::leftChild(current));
00428                                 
00429                                 if(addRightMostLeftChild != -1) {
00430                                     int rightMostLeft = rightMostChild(ItemHandler::leftChild(replaceWith));
00431                                     Q_ASSERT(rightMostLeft != -1);
00432 //                                     Q_ASSERT(item(rightMostLeft).ItemHandler::rightChild() == -1);
00433                                     Q_ASSERT(rightMostLeft < addRightMostLeftChild);
00434                                     ItemHandler::setRightChild(m_items[rightMostLeft], addRightMostLeftChild);
00435                                 }
00436                             }else{
00437                                 Q_ASSERT(addRightMostLeftChild == -1 || addRightMostLeftChild < replaceCurrentWith);
00438                                 ItemHandler::setLeftChild(replaceWith, addRightMostLeftChild);
00439                             }
00440                            }
00441                            
00442                            Q_ASSERT(ItemHandler::rightChild(current) == -1 || replaceCurrentWith < ItemHandler::rightChild(current));
00443                            ItemHandler::setRightChild(replaceWith, ItemHandler::rightChild(current));
00444                        }else{
00445                            //pick the right replacement, since it's more central
00446                            Q_ASSERT(rightReplaceCandidate != -1);
00447                            replaceCurrentWith = rightReplaceCandidate;
00448                            
00449                            Data& replaceWith(m_items[replaceCurrentWith]);
00450                            
00451                            if(replaceCurrentWith == ItemHandler::rightChild(current)) {
00452                                //The right child of replaceWith can just stay as it is, and we just need to add the left child
00453                                Q_ASSERT(ItemHandler::leftChild(replaceWith) == -1);
00454                            }else{
00455                             takeLeftMostChild(ItemHandler::rightChild(current));
00456                             
00457                             //Since we'll be clearing the item, we have to put this childsomewhere else. 
00458                             // Either make it our new "right" child, or make it the new right children "leftmost" child.
00459                             int addLeftMostRightChild = ItemHandler::rightChild(replaceWith);
00460                             
00461                             ItemHandler::setRightChild(replaceWith, -1);
00462                             
00463                             Q_ASSERT(ItemHandler::rightChild(replaceWith) == -1);
00464                             Q_ASSERT(ItemHandler::leftChild(replaceWith) == -1);
00465                             
00466                             if(ItemHandler::rightChild(current) != -1)
00467                             {
00468                                 Q_ASSERT(leftMostChild(ItemHandler::rightChild(current)) != replaceCurrentWith);
00469                                 Q_ASSERT(ItemHandler::rightChild(current) == -1 || replaceCurrentWith < ItemHandler::rightChild(current));
00470                                 ItemHandler::setRightChild(replaceWith, ItemHandler::rightChild(current));
00471                                 
00472                                 if(addLeftMostRightChild != -1) {
00473                                     int leftMostRight = leftMostChild(ItemHandler::rightChild(replaceWith));
00474                                     Q_ASSERT(leftMostRight != -1);
00475                                     Q_ASSERT(ItemHandler::leftChild(m_items[leftMostRight]) == -1);
00476                                     Q_ASSERT(addLeftMostRightChild < leftMostRight);
00477                                     ItemHandler::setLeftChild(m_items[leftMostRight], addLeftMostRightChild);
00478                                 }
00479                             }else{
00480                                 Q_ASSERT(addLeftMostRightChild == -1 || replaceCurrentWith < addLeftMostRightChild);
00481                                 ItemHandler::setRightChild(replaceWith, addLeftMostRightChild);
00482                             }
00483                            }
00484                            
00485                            Q_ASSERT(ItemHandler::leftChild(current) == -1 || ItemHandler::leftChild(current) < replaceCurrentWith);
00486                            ItemHandler::setLeftChild(replaceWith, ItemHandler::leftChild(current));
00487                        }
00488                        break;
00489                    }
00490                }
00491                
00492                //We can insert now
00493                //currentItem and previousItem are the two items that best enclose the target item
00494                 
00495 //                for(int a = currentLowerBound; a < currentUpperBound; ++a) {
00496 //                        Q_ASSERT(!ItemHandler::isFree(m_items[a]));
00497 //                }
00498                
00499                Q_ASSERT(currentItem < currentLowerBound || currentItem >= currentUpperBound);
00500 
00501                //If the current item is on a border of the bounds, it needs to be inserted in the right position.
00502                //Else, the current position already is right, and we only need to copy it in.
00503                if(currentLowerBound < currentUpperBound && (currentItem == currentLowerBound-1 || currentItem == currentUpperBound)) {
00504                  if(!insertSorted(m_add, currentItem, currentLowerBound, currentUpperBound, force)) {
00505                      return false;
00506                  }
00507                }else{
00508                  ItemHandler::copyTo(m_add, m_items[currentItem]);
00509                }
00510 
00511                m_applied = true;
00512                
00513                //First, take currentItem out of the chain, by replacing it with current.rightChild in the parent
00514                if(previousItem != -1) {
00515                    Data& previous(m_items[previousItem]);
00516                     if(ItemHandler::leftChild(previous) == currentItem) {
00517                         Q_ASSERT(replaceCurrentWith == -1 || replaceCurrentWith < previousItem);
00518                         ItemHandler::setLeftChild(previous, replaceCurrentWith);
00519                     } else if(ItemHandler::rightChild(previous) == currentItem) {
00520                         Q_ASSERT(replaceCurrentWith == -1 || previousItem < replaceCurrentWith);
00521                         ItemHandler::setRightChild(previous, replaceCurrentWith);
00522                     } else {
00523                         Q_ASSERT(0);
00524                     }
00525                } else {
00526                    *m_centralFreeItem = replaceCurrentWith;
00527                }
00528                
00529                return true;
00530                
00531                DEBUG_FREEITEM_COUNT
00532            }
00533         
00534         private:
00535            void verifyTreeConsistent(int position, int lowerBound, int upperBound) {
00536                if(position == -1)
00537                    return;
00538                Q_ASSERT(lowerBound <= position && position < upperBound);
00539                verifyTreeConsistent(ItemHandler::leftChild(m_items[position]), lowerBound, position);
00540                verifyTreeConsistent(ItemHandler::rightChild(m_items[position]), position+1, upperBound);
00541            }
00542             
00543             void debugFreeItemCount() {
00544                 uint count = 0;
00545                 for(uint a = 0; a < m_itemCount; ++a) {
00546                     if(isFree(m_items[a]))
00547                         ++count;
00548                 }
00549                 uint counted = countFreeItems(*m_centralFreeItem);
00550                 Q_ASSERT(count == counted);
00551             }
00552             
00553             QPair<int, int> leftAndRightRealItems(int pos) {
00554                 Q_ASSERT(ItemHandler::isFree(m_items[pos]));
00555                 int left = -1, right = -1;
00556                 for(int a = pos-1; a >= 0; --a) {
00557                     if(!ItemHandler::isFree(m_items[a])) {
00558                         left = a;
00559                         break;
00560                     }
00561                 }
00562                 for(uint a = pos+1; a < m_itemCount; ++a) {
00563                     if(!ItemHandler::isFree(m_items[a])) {
00564                         right = a;
00565                         break;
00566                     }
00567                 }
00568                 return qMakePair(left, right);
00569             }
00570             
00571             int buildFreeTree(int count, uint raster, int start) {
00572                 Q_ASSERT((start % raster) == (raster-1));
00573                 Q_ASSERT(count != 0);
00574                 Q_ASSERT(count <= (int)m_itemCount);
00575                 if(count == 1) {
00576                     ItemHandler::createFreeItem(m_items[start]);
00577                     return start;
00578                 }else{
00579                     int central = start + (count / 2) * raster;
00580                     int leftCount = count / 2;
00581                     int midCount = 1;
00582                     int rightCount = count - leftCount - midCount;
00583                     Q_ASSERT(leftCount + midCount <= count);
00584                     ItemHandler::createFreeItem(m_items[central]);
00585                     Q_ASSERT(ItemHandler::isFree(m_items[central]));
00586                     
00587                     int leftFreeTree = buildFreeTree(leftCount, raster, start);
00588                     Q_ASSERT(leftFreeTree == -1 || leftFreeTree < central);
00589                     ItemHandler::setLeftChild(m_items[central],  leftFreeTree );
00590                     
00591                     if(rightCount > 0) {
00592                         int rightFreeTree = buildFreeTree(rightCount, raster, central+raster);
00593                         Q_ASSERT(rightFreeTree == -1 || central < rightFreeTree);
00594                         ItemHandler::setRightChild(m_items[central], rightFreeTree );
00595                     }
00596                     
00597                     return central;
00598                 }
00599             }
00600             
00601             uint countFreeItems(int item) const {
00602                 if(item == -1)
00603                     return 0;
00604                 const Data& current(m_items[item]);
00605                 
00606                 return 1 + countFreeItems(ItemHandler::leftChild(current)) + countFreeItems(ItemHandler::rightChild(current));
00607             }
00608             
00609            int leftMostChild(int pos) const {
00610                while(1) {
00611                    if(ItemHandler::leftChild(m_items[pos]) != -1)
00612                        pos = ItemHandler::leftChild(m_items[pos]);
00613                    else
00614                        return pos;
00615                }
00616            }
00617            
00618            int takeLeftMostChild(int pos) const {
00619                int parent = -1;
00620                while(1) {
00621                    if(ItemHandler::leftChild(m_items[pos]) != -1) {
00622                        parent = pos;
00623                        pos = ItemHandler::leftChild(m_items[pos]);
00624                    } else {
00625                        ItemHandler::setLeftChild(m_items[parent], -1);
00626                        return pos;
00627                    }
00628                }
00629            }
00630 
00631            int rightMostChild(int pos) const {
00632                while(1) {
00633                    if(ItemHandler::rightChild(m_items[pos]) != -1)
00634                        pos = ItemHandler::rightChild(m_items[pos]);
00635                    else
00636                        return pos;
00637                }
00638            }
00639            
00640            int takeRightMostChild(int pos) const {
00641                int parent = -1;
00642                while(1) {
00643                    if(ItemHandler::rightChild(m_items[pos]) != -1) {
00644                        parent = pos;
00645                        pos = ItemHandler::rightChild(m_items[pos]);
00646                    } else {
00647                        ItemHandler::setRightChild(m_items[parent], -1);
00648                        return pos;
00649                    }
00650                }
00651            }
00652 
00653            void insertBubbleSorted(const Data& data, int pos) {
00654                 //Since we don't know how the target is enclosed, just do naive bubble sort
00655                 ItemHandler::copyTo(data, m_items[pos]);
00656                 while(1) {
00657                     int prev = pos-1;
00658                     int next = pos+1;
00659                     if(prev >= 0 && !ItemHandler::isFree(m_items[prev]) && m_items[pos] < m_items[prev]) {
00660                         Data backup(m_items[prev]);
00661                         m_items[prev] = m_items[pos];
00662                         m_items[pos] = backup;
00663                         pos = prev;
00664                     }else if(next < m_itemCount && !ItemHandler::isFree(m_items[next]) && m_items[next] < m_items[pos]) {
00665                         Data backup(m_items[next]);
00666                         m_items[next] = m_items[pos];
00667                         m_items[pos] = backup;
00668                         pos = next;
00669                     }else{
00670                         break;
00671                     }
00672                 }
00673            }
00674            
00676            inline int maxMoveAround() const {
00677                return increaseFraction * rebuildIfInsertionMoreExpensive;
00678            }
00679            
00683            bool insertSorted(const Data& data, int pos, int start, int end, bool force) {
00684                
00685                if(pos < start)
00686                    start = pos;
00687                if(pos >= end)
00688                    end = pos+1;
00689                
00690 /*               for(int a = start; a < end; ++a) {
00691                    if(a != pos) {
00692                        Q_ASSERT(!ItemHandler::isFree(m_items[a]));
00693                    }
00694                }*/
00695                EmbeddedTreeAlgorithms<Data, ItemHandler> alg(m_items, m_itemCount, *m_centralFreeItem);
00696                int bound = alg.lowerBound(data, start, end);
00697                //Now find the position that should be taken
00698                if(bound == -1)
00699                    bound = end;
00700                
00701                //Now our item should end up right before bound
00702 
00703                int target;
00704                //bound cannot be pos, because pos is invalid
00705                Q_ASSERT(bound != pos);
00706 
00707                 //Shuffle around the item at the free pos, so reference counting in constructors/destructors is not screwed up
00708                 char backup[sizeof(Data)];
00709                 memcpy(backup, m_items+pos, sizeof(Data));
00710                 
00711                if(bound < pos) {
00712                    if(!force && pos-bound > maxMoveAround()) {
00713 //                         kDebug() << "increasing because" << pos-bound << ">" << maxMoveAround() << "left free items:" << countFreeItems(*m_centralFreeItem) << "target free items:" << (m_itemCount-countFreeItems(*m_centralFreeItem))/increaseFraction;
00714                        return false;
00715                    }
00716                    //Move [bound, pos) one to right, and insert at bound
00717                     memmove(m_items+bound+1, m_items+bound, sizeof(Data)*(pos-bound));
00718                     target = bound;
00719                }else {
00720                    Q_ASSERT(bound > pos);
00721                    if(!force && bound-pos-1 > maxMoveAround()) {
00722 //                         kDebug() << "increasing because" << bound-pos-1 << ">" << maxMoveAround() << "left free items:" << countFreeItems(*m_centralFreeItem)<< "target free items:" << (m_itemCount-countFreeItems(*m_centralFreeItem))/increaseFraction;
00723                        return false;
00724                    }
00725                    //Move (pos, bound) one to left, and insert at bound-1
00726                     memmove(m_items+pos, m_items+pos+1, sizeof(Data)*(bound-pos-1));
00727                     target = bound-1;
00728                }
00729                memcpy(m_items+target, backup, sizeof(Data));
00730                
00731                ItemHandler::copyTo(data, m_items[target]);
00732                return true;
00733            }
00734            
00735            const Data& m_add;
00736            Data* m_items;
00737            uint m_itemCount;
00738            int* m_centralFreeItem;
00739            bool m_applied, m_needResize;
00740     };
00741 
00751     template<class Data, class ItemHandler, int increaseFraction = 5 >
00752     class EmbeddedTreeRemoveItem {
00753 
00754         public:
00755             
00756             EmbeddedTreeRemoveItem(Data* items, uint itemCount, int& centralFreeItem, const Data& remove) : m_remove(remove), m_items(items), m_itemCount(itemCount), m_centralFreeItem(&centralFreeItem), m_insertedAtDepth(0) {
00757                  apply();
00758             }
00759 
00760             ~EmbeddedTreeRemoveItem() {
00761             }
00762 
00765             uint newItemCount() const {
00766                 uint maxFreeItems = ((m_itemCount / increaseFraction)*3)/2 + 1;
00767                 //First we approximate the count of free items using the insertion depth
00768                 if((1u << m_insertedAtDepth) >= maxFreeItems) {
00769                     uint freeCount = countFreeItems(*m_centralFreeItem);
00770                     if(freeCount > maxFreeItems || freeCount == m_itemCount) {
00771                         return m_itemCount - freeCount;
00772                     }
00773                 }
00774                 
00775                 return m_itemCount;
00776             }
00777             
00779             void transferData(Data* newItems, uint newCount, int* newCentralFree = 0) {
00780                 DEBUG_FREEITEM_COUNT
00781                 //We only transfer into a new list when all the free items are used up
00782                 
00783                 //Create a list where only the non-free items exist
00784                 uint offset = 0;
00785                 for(uint a = 0; a < m_itemCount; ++a) {
00786                     if(!ItemHandler::isFree(m_items[a])) {
00787                         newItems[offset] = m_items[a];
00788                         ++offset;
00789                     }
00790                 }
00791                 Q_ASSERT(offset == newCount);
00792 
00793                 if(newCentralFree)
00794                     m_centralFreeItem = newCentralFree;
00795                 *m_centralFreeItem = -1;
00796                 m_items = newItems;
00797                 m_itemCount = newCount;
00798                 DEBUG_FREEITEM_COUNT
00799             }
00800             
00801         private:
00802            void verifyTreeConsistent(int position, int lowerBound, int upperBound) {
00803                 if(position == -1)
00804                     return;
00805                 Q_ASSERT(lowerBound <= position && position < upperBound);
00806                 verifyTreeConsistent(ItemHandler::leftChild(m_items[position]), lowerBound, position);
00807                 verifyTreeConsistent(ItemHandler::rightChild(m_items[position]), position+1, upperBound);
00808            }
00809             
00810             uint countFreeItems(int item) const {
00811                 if(item == -1)
00812                     return 0;
00813                 const Data& current(m_items[item]);
00814                 
00815                 return 1 + countFreeItems(ItemHandler::leftChild(current)) + countFreeItems(ItemHandler::rightChild(current));
00816             }
00817             
00818             int findItem(const Data& data, uint start, uint end) {
00819                 EmbeddedTreeAlgorithms<Data, ItemHandler> alg(m_items, m_itemCount, *m_centralFreeItem);
00820                 return alg.indexOf(data, start, end);
00821             }
00822             
00823            void apply() {
00824                DEBUG_FREEITEM_COUNT
00825                
00826                int removeIndex = findItem(m_remove, 0, m_itemCount);
00827                Q_ASSERT(removeIndex != -1);
00828                Q_ASSERT(!ItemHandler::isFree(m_items[removeIndex]));
00829                
00830                //Find the free item that is nearest to the target position in the item order
00831                int previousItem = -1;
00832                int currentItem = *m_centralFreeItem;
00833                
00834                int lowerBound = 0; //The minimum position the searched item can have
00835                int upperBound = m_itemCount; //The lowest known position the searched item can _not_ have
00836                
00837                if(*m_centralFreeItem == -1) {
00838                    *m_centralFreeItem = removeIndex;
00839                    Q_ASSERT(*m_centralFreeItem != -1);
00840                    ItemHandler::createFreeItem(m_items[*m_centralFreeItem]);
00841                    return;
00842                }
00843                
00844                //Now go down the chain, always into the items direction
00847                while(1) {
00848                    Q_ASSERT(removeIndex != currentItem);
00849                    Data& current(m_items[currentItem]);
00850                    ++m_insertedAtDepth;
00851                    if(removeIndex < currentItem) {
00852                        upperBound = currentItem;
00853                        //Follow left child
00854                        if(ItemHandler::leftChild(current) != -1) {
00855                            //Continue traversing
00856                            previousItem = currentItem;
00857                            currentItem = ItemHandler::leftChild(current);
00858                            Q_ASSERT(currentItem >= lowerBound && currentItem < upperBound);
00859                        }else{
00860                            //The to-be deleted item is before current, and can be added as left child to current 
00861                            int item = findItem(m_remove, lowerBound, upperBound);
00862                            Q_ASSERT(item == removeIndex);
00863                            ItemHandler::createFreeItem(m_items[item]);
00864                            Q_ASSERT(item == -1 || item < currentItem);
00865                            ItemHandler::setLeftChild(current, item);
00866                            Q_ASSERT(item >= lowerBound && item < upperBound);
00867                            break;
00868                        }
00869                    }else{
00870                        lowerBound = currentItem+1;
00871                        //Follow right child
00872                        if(ItemHandler::rightChild(current) != -1) {
00873                            //Continue traversing
00874                            previousItem = currentItem;
00875                            currentItem = ItemHandler::rightChild(current);
00876                            Q_ASSERT(currentItem >= lowerBound && currentItem < upperBound);
00877                        }else{
00878                            //The to-be deleted item is behind current, and can be added as right child to current 
00879                            int item = findItem(m_remove, lowerBound, upperBound);
00880                            Q_ASSERT(item == removeIndex);
00881                            ItemHandler::createFreeItem(m_items[item]);
00882                            Q_ASSERT(item == -1 || currentItem < item);
00883                            ItemHandler::setRightChild(current, item);
00884                            Q_ASSERT(item >= lowerBound && item < upperBound);
00885                            break;
00886                        }
00887                    }
00888                }
00889                
00890                DEBUG_FREEITEM_COUNT
00891            }
00892             
00893            void debugFreeItemCount() {
00894                uint count = 0;
00895                for(uint a = 0; a < m_itemCount; ++a) {
00896                    if(ItemHandler::isFree(m_items[a]))
00897                        ++count;
00898                }
00899                uint counted = countFreeItems(*m_centralFreeItem);
00900                Q_ASSERT(count == counted);
00901            }
00902            
00903            const Data& m_remove;
00904            Data* m_items;
00905            uint m_itemCount;
00906            int* m_centralFreeItem;
00907            int m_insertedAtDepth;
00908     };
00909 }
00910 
00911 #endif

util

Skip menu "util"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDevelop Platform Libraries

Skip menu "KDevelop Platform Libraries"
  • interfaces
  • language
  •   codegen
  •   duchain
  •   editor
  • outputview
  • project
  • shell
  • sublime
  • util
  • vcs
Generated for KDevelop Platform Libraries by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal