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