LocHeap.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /* Copyright (c) 2015, 2020 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. namespace loc_util {
  31. class LocHeapNode {
  32. friend class LocHeap;
  33. // size of of the subtree, excluding self, 1 if no subtree
  34. int mSize;
  35. LocHeapNode* mLeft;
  36. LocHeapNode* mRight;
  37. LocRankable* mData;
  38. public:
  39. inline LocHeapNode(LocRankable& data) :
  40. mSize(1), mLeft(NULL), mRight(NULL), mData(&data) {}
  41. ~LocHeapNode();
  42. // this only swaps the data of the two nodes, so no
  43. // detach / re-attached is necessary
  44. void swap(LocHeapNode& node);
  45. LocRankable* detachData();
  46. // push a node into the tree stucture, keeping sorted by rank
  47. void push(LocHeapNode& node);
  48. // pop the head node out of the tree stucture. keeping sorted by rank
  49. static LocHeapNode* pop(LocHeapNode*& top);
  50. // remove a specific node from the tree
  51. // returns the pointer to the node removed, which would be either the
  52. // same as input (if successfully removed); or NULL (if failed).
  53. static LocHeapNode* remove(LocHeapNode*& top, LocRankable& data);
  54. // convenience method to compare data ranking
  55. inline bool outRanks(LocHeapNode& node) { return mData->outRanks(*node.mData); }
  56. inline bool outRanks(LocRankable& data) { return mData->outRanks(data); }
  57. // checks if mSize is correct, AND this node is the highest ranking
  58. // of the entire subtree
  59. bool checkNodes();
  60. inline int getSize() { return mSize; }
  61. };
  62. inline
  63. LocHeapNode::~LocHeapNode() {
  64. if (mLeft) {
  65. delete mLeft;
  66. mLeft = NULL;
  67. }
  68. if (mRight) {
  69. delete mRight;
  70. mRight = NULL;
  71. }
  72. if (mData) {
  73. mData = NULL;
  74. }
  75. }
  76. inline
  77. void LocHeapNode::swap(LocHeapNode& node) {
  78. LocRankable* tmpData = node.mData;
  79. node.mData = mData;
  80. mData = tmpData;
  81. }
  82. inline
  83. LocRankable* LocHeapNode::detachData() {
  84. LocRankable* data = mData;
  85. mData = NULL;
  86. return data;
  87. }
  88. // push keeps the tree sorted by rank, it also tries to balance the
  89. // tree by adding the new node to the smaller of the subtrees.
  90. // The pointer to the tree and internal links never change. If the
  91. // mData of tree top ranks lower than that of the incoming node,
  92. // mData will be swapped with that of the incoming node to ensure
  93. // ranking, no restructuring the container nodes.
  94. void LocHeapNode::push(LocHeapNode& node) {
  95. // ensure the current node ranks higher than in the incoming one
  96. if (node.outRanks(*this)) {
  97. swap(node);
  98. }
  99. // now drop the new node (ensured lower than *this) into a subtree
  100. if (NULL == mLeft) {
  101. mLeft = &node;
  102. } else if (NULL == mRight) {
  103. mRight = &node;
  104. } else if (mLeft->mSize <= mRight->mSize) {
  105. mLeft->push(node);
  106. } else {
  107. mRight->push(node);
  108. }
  109. mSize++;
  110. }
  111. // pop keeps the tree sorted by rank, but it does not try to balance
  112. // the tree. It recursively swaps with the higher ranked top of the
  113. // subtrees.
  114. // The return is a popped out node from leaf level, that has the data
  115. // swapped all the way down from the top. The pinter to the tree and
  116. // internal links will not be changed or restructured, except for the
  117. // node that is popped out.
  118. // If the return pointer == this, this the last node in the tree.
  119. LocHeapNode* LocHeapNode::pop(LocHeapNode*& top) {
  120. // we know the top has the highest ranking at this point, else
  121. // the tree is broken. This top will be popped out. But we need
  122. // a node from the left or right child, whichever ranks higher,
  123. // to replace the current top. This then will need to be done
  124. // recursively to the leaf level. So we swap the mData of the
  125. // current top node all the way down to the leaf level.
  126. LocHeapNode* poppedNode = top;
  127. // top is losing a node in its subtree
  128. top->mSize--;
  129. if (top->mLeft || top->mRight) {
  130. // if mLeft is NULL, mRight for sure is NOT NULL, take that;
  131. // else if mRight is NULL, mLeft for sure is NOT, take that;
  132. // else we take the address of whatever has higher ranking mData
  133. LocHeapNode*& subTop = (NULL == top->mLeft) ? top->mRight :
  134. ((NULL == top->mRight) ? top->mLeft :
  135. (top->mLeft->outRanks(*(top->mRight)) ? top->mLeft : top->mRight));
  136. // swap mData, the tree top gets updated with the new data.
  137. top->swap(*subTop);
  138. // pop out from the subtree
  139. poppedNode = pop(subTop);
  140. } else {
  141. // if the top has only single node
  142. // detach the poppedNode from the tree
  143. // subTop is the reference of ether mLeft or mRight
  144. // NOT a local stack pointer. so it MUST be NULL'ed here.
  145. top = NULL;
  146. }
  147. return poppedNode;
  148. }
  149. // navigating through the tree and find the node that hass the input
  150. // data. Since this is a heap, we do recursive linear search.
  151. // returns the pointer to the node removed, which would be either the
  152. // same as input (if successfully removed); or NULL (if failed).
  153. LocHeapNode* LocHeapNode::remove(LocHeapNode*& top, LocRankable& data) {
  154. LocHeapNode* removedNode = NULL;
  155. // this is the node, by address
  156. if (&data == (LocRankable*)(top->mData)) {
  157. // pop this node out
  158. removedNode = pop(top);
  159. } else if (!data.outRanks(*top->mData)) {
  160. // subtrees might have this node
  161. if (top->mLeft) {
  162. removedNode = remove(top->mLeft, data);
  163. }
  164. // if we did not find in mLeft, and mRight is not empty
  165. if (!removedNode && top->mRight) {
  166. removedNode = remove(top->mRight, data);
  167. }
  168. // top lost a node in its subtree
  169. if (removedNode) {
  170. top->mSize--;
  171. }
  172. }
  173. return removedNode;
  174. }
  175. // checks if mSize is correct, AND this node is the highest ranking
  176. // of the entire subtree
  177. bool LocHeapNode::checkNodes() {
  178. // size of the current subtree
  179. int totalSize = mSize;
  180. if (mLeft) {
  181. // check the consistency of left subtree
  182. if (mLeft->outRanks(*this) || !mLeft->checkNodes()) {
  183. return false;
  184. }
  185. // subtract the size of left subtree (with subtree head)
  186. totalSize -= mLeft->mSize;
  187. }
  188. if (mRight) {
  189. // check the consistency of right subtree
  190. if (mRight->outRanks(*this) || !mRight->checkNodes()) {
  191. return false;
  192. }
  193. // subtract the size of right subtree (with subtree head)
  194. totalSize -= mRight->mSize;
  195. }
  196. // for the tree nodes to consistent, totalSize must be 1 now
  197. return totalSize == 1;
  198. }
  199. LocHeap::~LocHeap() {
  200. if (mTree) {
  201. delete mTree;
  202. }
  203. }
  204. void LocHeap::push(LocRankable& node) {
  205. LocHeapNode* heapNode = new LocHeapNode(node);
  206. if (!mTree) {
  207. mTree = heapNode;
  208. } else {
  209. mTree->push(*heapNode);
  210. }
  211. }
  212. LocRankable* LocHeap::peek() {
  213. LocRankable* top = NULL;
  214. if (mTree) {
  215. top = mTree->mData;
  216. }
  217. return top;
  218. }
  219. LocRankable* LocHeap::pop() {
  220. LocRankable* locNode = NULL;
  221. if (mTree) {
  222. // mTree may become NULL after this call
  223. LocHeapNode* heapNode = LocHeapNode::pop(mTree);
  224. locNode = heapNode->detachData();
  225. delete heapNode;
  226. }
  227. return locNode;
  228. }
  229. LocRankable* LocHeap::remove(LocRankable& rankable) {
  230. LocRankable* locNode = NULL;
  231. if (mTree) {
  232. // mTree may become NULL after this call
  233. LocHeapNode* heapNode = LocHeapNode::remove(mTree, rankable);
  234. if (heapNode) {
  235. locNode = heapNode->detachData();
  236. delete heapNode;
  237. }
  238. }
  239. return locNode;
  240. }
  241. } // namespace loc_util
  242. #ifdef __LOC_UNIT_TEST__
  243. bool LocHeap::checkTree() {
  244. return ((NULL == mTree) || mTree->checkNodes());
  245. }
  246. uint32_t LocHeap::getTreeSize() {
  247. return (NULL == mTree) ? 0 : mTree->getSize();
  248. }
  249. #endif