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