Home | History | Annotate | Download | only in utils
      1 /* Copyright (c) 2015, The Linux Foundation. All rights reserved.
      2  *
      3  * Redistribution and use in source and binary forms, with or without
      4  * modification, are permitted provided that the following conditions are
      5  * met:
      6  *     * Redistributions of source code must retain the above copyright
      7  *       notice, this list of conditions and the following disclaimer.
      8  *     * Redistributions in binary form must reproduce the above
      9  *       copyright notice, this list of conditions and the following
     10  *       disclaimer in the documentation and/or other materials provided
     11  *       with the distribution.
     12  *     * Neither the name of The Linux Foundation, nor the names of its
     13  *       contributors may be used to endorse or promote products derived
     14  *       from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  *
     28  */
     29 #include <LocHeap.h>
     30 
     31 class LocHeapNode {
     32     friend class LocHeap;
     33 
     34     // size of of the subtree, excluding self, 1 if no subtree
     35     int mSize;
     36     LocHeapNode* mLeft;
     37     LocHeapNode* mRight;
     38     LocRankable* mData;
     39 public:
     40     inline LocHeapNode(LocRankable& data) :
     41         mSize(1), mLeft(NULL), mRight(NULL), mData(&data) {}
     42     ~LocHeapNode();
     43 
     44     // this only swaps the data of the two nodes, so no
     45     // detach / re-attached is necessary
     46     void swap(LocHeapNode& node);
     47 
     48     LocRankable* detachData();
     49 
     50     // push a node into the tree stucture, keeping sorted by rank
     51     void push(LocHeapNode& node);
     52 
     53     // pop the head node out of the tree stucture. keeping sorted by rank
     54     static LocHeapNode* pop(LocHeapNode*& top);
     55 
     56     // remove a specific node from the tree
     57     // returns the pointer to the node removed, which would be either the
     58     //         same as input (if successfully removed); or NULL (if failed).
     59     static LocHeapNode* remove(LocHeapNode*& top, LocRankable& data);
     60 
     61     // convenience method to compare data ranking
     62     inline bool outRanks(LocHeapNode& node) { return mData->outRanks(*node.mData); }
     63     inline bool outRanks(LocRankable& data) { return mData->outRanks(data); }
     64 
     65     // checks if mSize is correct, AND this node is the highest ranking
     66     // of the entire subtree
     67     bool checkNodes();
     68 
     69     inline int getSize() { return mSize; }
     70 };
     71 
     72 inline
     73 LocHeapNode::~LocHeapNode() {
     74     if (mLeft) {
     75         delete mLeft;
     76         mLeft = NULL;
     77     }
     78     if (mRight) {
     79         delete mRight;
     80         mRight = NULL;
     81     }
     82     if (mData) {
     83         mData = NULL;
     84     }
     85 }
     86 
     87 inline
     88 void LocHeapNode::swap(LocHeapNode& node) {
     89     LocRankable* tmpData = node.mData;
     90     node.mData = mData;
     91     mData = tmpData;
     92 }
     93 
     94 inline
     95 LocRankable* LocHeapNode::detachData()  {
     96     LocRankable* data = mData;
     97     mData = NULL;
     98     return data;
     99 }
    100 
    101 // push keeps the tree sorted by rank, it also tries to balance the
    102 // tree by adding the new node to the smaller of the subtrees.
    103 // The pointer to the tree and internal links never change. If the
    104 // mData of tree top ranks lower than that of the incoming node,
    105 // mData will be swapped with that of the incoming node to ensure
    106 // ranking, no restructuring the container nodes.
    107 void LocHeapNode::push(LocHeapNode& node) {
    108     // ensure the current node ranks higher than in the incoming one
    109     if (node.outRanks(*this)) {
    110         swap(node);
    111     }
    112 
    113     // now drop the new node (ensured lower than *this) into a subtree
    114     if (NULL == mLeft) {
    115         mLeft = &node;
    116     } else if (NULL == mRight) {
    117         mRight = &node;
    118     } else if (mLeft->mSize <= mRight->mSize) {
    119         mLeft->push(node);
    120     } else {
    121         mRight->push(node);
    122     }
    123     mSize++;
    124 }
    125 
    126 // pop keeps the tree sorted by rank, but it does not try to balance
    127 // the tree. It recursively swaps with the higher ranked top of the
    128 // subtrees.
    129 // The return is a popped out node from leaf level, that has the data
    130 // swapped all the way down from the top. The pinter to the tree and
    131 // internal links will not be changed or restructured, except for the
    132 // node that is popped out.
    133 // If the return pointer == this, this the last node in the tree.
    134 LocHeapNode* LocHeapNode::pop(LocHeapNode*& top) {
    135     // we know the top has the highest ranking at this point, else
    136     // the tree is broken. This top will be popped out.  But we need
    137     // a node from the left or right child, whichever ranks higher,
    138     // to replace the current top. This then will need to be done
    139     // recursively to the leaf level. So we swap the mData of the
    140     // current top node all the way down to the leaf level.
    141     LocHeapNode* poppedNode = top;
    142     // top is losing a node in its subtree
    143     top->mSize--;
    144     if (top->mLeft || top->mRight) {
    145         // if mLeft is NULL, mRight for sure is NOT NULL, take that;
    146         // else if mRight is NULL, mLeft for sure is NOT, take that;
    147         // else we take the address of whatever has higher ranking mData
    148         LocHeapNode*& subTop = (NULL == top->mLeft) ? top->mRight :
    149             ((NULL == top->mRight) ? top->mLeft :
    150              (top->mLeft->outRanks(*(top->mRight)) ? top->mLeft : top->mRight));
    151         // swap mData, the tree top gets updated with the new data.
    152         top->swap(*subTop);
    153         // pop out from the subtree
    154         poppedNode = pop(subTop);
    155     } else {
    156         // if the top has only single node
    157         // detach the poppedNode from the tree
    158         // subTop is the reference of ether mLeft or mRight
    159         // NOT a local stack pointer. so it MUST be NULL'ed here.
    160         top = NULL;
    161     }
    162 
    163     return poppedNode;
    164 }
    165 
    166 // navigating through the tree and find the node that hass the input
    167 // data. Since this is a heap, we do recursive linear search.
    168 // returns the pointer to the node removed, which would be either the
    169 //         same as input (if successfully removed); or NULL (if failed).
    170 LocHeapNode* LocHeapNode::remove(LocHeapNode*& top, LocRankable& data) {
    171     LocHeapNode* removedNode = NULL;
    172     // this is the node, by address
    173     if (&data == (LocRankable*)(top->mData)) {
    174         // pop this node out
    175         removedNode = pop(top);
    176     } else if (!data.outRanks(*top->mData)) {
    177         // subtrees might have this node
    178         if (top->mLeft) {
    179             removedNode = remove(top->mLeft, data);
    180         }
    181         // if we did not find in mLeft, and mRight is not empty
    182         if (!removedNode && top->mRight) {
    183             removedNode = remove(top->mRight, data);
    184         }
    185 
    186         // top lost a node in its subtree
    187         if (removedNode) {
    188             top->mSize--;
    189         }
    190     }
    191 
    192     return removedNode;
    193 }
    194 
    195 // checks if mSize is correct, AND this node is the highest ranking
    196 // of the entire subtree
    197 bool LocHeapNode::checkNodes() {
    198     // size of the current subtree
    199     int totalSize = mSize;
    200     if (mLeft) {
    201         // check the consistency of left subtree
    202         if (mLeft->outRanks(*this) || !mLeft->checkNodes()) {
    203             return false;
    204         }
    205         // subtract the size of left subtree (with subtree head)
    206         totalSize -= mLeft->mSize;
    207     }
    208 
    209     if (mRight) {
    210         // check the consistency of right subtree
    211         if (mRight->outRanks(*this) || !mRight->checkNodes()) {
    212             return false;
    213         }
    214         // subtract the size of right subtree (with subtree head)
    215         totalSize -= mRight->mSize;
    216     }
    217 
    218     // for the tree nodes to consistent, totalSize must be 1 now
    219     return totalSize == 1;
    220 }
    221 
    222 LocHeap::~LocHeap() {
    223     if (mTree) {
    224         delete mTree;
    225     }
    226 }
    227 
    228 void LocHeap::push(LocRankable& node) {
    229     LocHeapNode* heapNode = new LocHeapNode(node);
    230     if (!mTree) {
    231         mTree = heapNode;
    232     } else {
    233         mTree->push(*heapNode);
    234     }
    235 }
    236 
    237 LocRankable* LocHeap::peek() {
    238     LocRankable* top = NULL;
    239     if (mTree) {
    240         top = mTree->mData;
    241     }
    242     return top;
    243 }
    244 
    245 LocRankable* LocHeap::pop() {
    246     LocRankable* locNode = NULL;
    247     if (mTree) {
    248         // mTree may become NULL after this call
    249         LocHeapNode* heapNode = LocHeapNode::pop(mTree);
    250         locNode = heapNode->detachData();
    251         delete heapNode;
    252     }
    253     return locNode;
    254 }
    255 
    256 LocRankable* LocHeap::remove(LocRankable& rankable) {
    257     LocRankable* locNode = NULL;
    258     if (mTree) {
    259         // mTree may become NULL after this call
    260         LocHeapNode* heapNode = LocHeapNode::remove(mTree, rankable);
    261         if (heapNode) {
    262             locNode = heapNode->detachData();
    263             delete heapNode;
    264         }
    265     }
    266     return locNode;
    267 }
    268 
    269 #ifdef __LOC_UNIT_TEST__
    270 bool LocHeap::checkTree() {
    271     return ((NULL == mTree) || mTree->checkNodes());
    272 }
    273 uint32_t LocHeap::getTreeSize() {
    274     return (NULL == mTree) ? 0 : mTree->getSize();
    275 }
    276 #endif
    277 
    278 #ifdef __LOC_DEBUG__
    279 
    280 #include <stdio.h>
    281 #include <stdlib.h>
    282 #include <time.h>
    283 
    284 class LocHeapDebug : public LocHeap {
    285 public:
    286     bool checkTree() {
    287         return ((NULL == mTree) || mTree->checkNodes());
    288     }
    289 
    290     uint32_t getTreeSize() {
    291         return (NULL == mTree) ? 0 : (mTree->getSize());
    292     }
    293 };
    294 
    295 class LocHeapDebugData : public LocRankable {
    296     const int mID;
    297 public:
    298     LocHeapDebugData(int id) : mID(id) {}
    299     inline virtual int ranks(LocRankable& rankable) {
    300         LocHeapDebugData* testData = dynamic_cast<LocHeapDebugData*>(&rankable);
    301         return testData->mID - mID;
    302     }
    303 };
    304 
    305 // For Linux command line testing:
    306 // compilation: g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../vendor/qcom/proprietary/gps-internal/unit-tests/fakes_for_host -I../../../../system/core/include LocHeap.cpp
    307 // test: valgrind --leak-check=full ./a.out 100
    308 int main(int argc, char** argv) {
    309     srand(time(NULL));
    310     int tries = atoi(argv[1]);
    311     int checks = tries >> 3;
    312     LocHeapDebug heap;
    313     int treeSize = 0;
    314 
    315     for (int i = 0; i < tries; i++) {
    316         if (i % checks == 0 && !heap.checkTree()) {
    317             printf("tree check failed before %dth op\n", i);
    318         }
    319         int r = rand();
    320 
    321         if (r & 1) {
    322             LocHeapDebugData* data = new LocHeapDebugData(r >> 1);
    323             heap.push(dynamic_cast<LocRankable&>(*data));
    324             treeSize++;
    325         } else {
    326             LocRankable* rankable = heap.pop();
    327             if (rankable) {
    328                 delete rankable;
    329             }
    330             treeSize ? treeSize-- : 0;
    331         }
    332 
    333         printf("%s: %d == %d\n", (r&1)?"push":"pop", treeSize, heap.getTreeSize());
    334         if (treeSize != heap.getTreeSize()) {
    335             printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
    336             tries = i+1;
    337             break;
    338         }
    339     }
    340 
    341     if (!heap.checkTree()) {
    342         printf("!!!!!!!!!!tree check failed at the end after %d ops!!!!!!!\n", tries);
    343     } else {
    344         printf("success!\n");
    345     }
    346 
    347     for (LocRankable* data = heap.pop(); NULL != data; data = heap.pop()) {
    348         delete data;
    349     }
    350 
    351     return 0;
    352 }
    353 
    354 #endif
    355