blob: 4d047e4c1a41ae2371da6d2a47de58ddf7f15f4e [file] [log] [blame]
Michael Bestas3a0209e2023-05-04 01:15:47 +03001/* 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
31namespace loc_util {
32
33class 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;
41public:
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
64 inline bool outRanks(LocHeapNode& node) { return mData->outRanks(*node.mData); }
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
71 inline int getSize() { return mSize; }
72};
73
74inline
75LocHeapNode::~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
89inline
90void LocHeapNode::swap(LocHeapNode& node) {
91 LocRankable* tmpData = node.mData;
92 node.mData = mData;
93 mData = tmpData;
94}
95
96inline
97LocRankable* 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.
109void 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.
136LocHeapNode* 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).
172LocHeapNode* 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
199bool 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
224LocHeap::~LocHeap() {
225 if (mTree) {
226 delete mTree;
227 }
228}
229
230void 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
239LocRankable* LocHeap::peek() {
240 LocRankable* top = NULL;
241 if (mTree) {
242 top = mTree->mData;
243 }
244 return top;
245}
246
247LocRankable* 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
258LocRankable* 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__
274bool LocHeap::checkTree() {
275 return ((NULL == mTree) || mTree->checkNodes());
276}
277uint32_t LocHeap::getTreeSize() {
278 return (NULL == mTree) ? 0 : mTree->getSize();
279}
280#endif