SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
HexFiend/HFAnnotatedTree.m
1 //
2 // HFAnnotatedTree.m
3 // HexFiend_2
4 //
5 // Copyright 2010 ridiculous_fish. All rights reserved.
6 //
7
8 #import "HFAnnotatedTree.h"
9
10 #if NDEBUG
11 #define VERIFY_INTEGRITY() do { } while (0)
12 #else
13 #define VERIFY_INTEGRITY() [self verifyIntegrity]
14 #endif
15
16 /* HFAnnotatedTree is an AA tree. */
17
18 static unsigned long long null_annotater(id left, id right) { USE(left); USE(right); return 0; }
19 static void skew(HFAnnotatedTreeNode *node, HFAnnotatedTree *tree);
20 static BOOL split(HFAnnotatedTreeNode *oldparent, HFAnnotatedTree *tree);
21 static void rebalanceAfterLeafAdd(HFAnnotatedTreeNode *n, HFAnnotatedTree *tree);
22 static void delete(HFAnnotatedTreeNode *n, HFAnnotatedTree *tree);
23 static void verify_integrity(HFAnnotatedTreeNode *n);
24
25 static HFAnnotatedTreeNode *next_node(HFAnnotatedTreeNode *node);
26
27 static void insert(HFAnnotatedTreeNode *root, HFAnnotatedTreeNode *node, HFAnnotatedTree *tree);
28
29 static inline HFAnnotatedTreeNode *get_parent(HFAnnotatedTreeNode *node);
30 static inline HFAnnotatedTreeNode *get_root(HFAnnotatedTree *tree);
31 static inline HFAnnotatedTreeNode *create_root(void);
32 static inline HFAnnotatedTreeAnnotaterFunction_t get_annotater(HFAnnotatedTree *tree);
33
34 static void reannotate(HFAnnotatedTreeNode *node, HFAnnotatedTree *tree);
35
36 static HFAnnotatedTreeNode *first_node(HFAnnotatedTreeNode *node);
37
38 static HFAnnotatedTreeNode *left_child(HFAnnotatedTreeNode *node);
39 static HFAnnotatedTreeNode *right_child(HFAnnotatedTreeNode *node);
40
41 @implementation HFAnnotatedTree
42
43 - (instancetype)initWithAnnotater:(HFAnnotatedTreeAnnotaterFunction_t)annot {
44 self = [super init];
45 annotater = annot ? annot : null_annotater;
46 /* root is always an HFAnnotatedTreeNode with a left child but no right child */
47 root = create_root();
48 return self;
49 }
50
51 - (void)dealloc {
52 [root release];
53 [super dealloc];
54 }
55
56 - (id)rootNode {
57 return root;
58 }
59
60 - (id)firstNode {
61 return first_node(root);
62 }
63
64 - (id)mutableCopyWithZone:(NSZone *)zone {
65 HFAnnotatedTree *copied = [[[self class] alloc] init];
66 copied->annotater = annotater;
67 [copied->root release];
68 copied->root = [root mutableCopyWithZone:zone];
69 return copied;
70 }
71
72 - (BOOL)isEmpty {
73 /* We're empty if our root has no children. */
74 return left_child(root) == nil && right_child(root) == nil;
75 }
76
77 - (void)insertNode:(HFAnnotatedTreeNode *)node {
78 HFASSERT(node != nil);
79 HFASSERT(get_parent(node) == nil);
80 /* Insert into the root */
81 insert(root, [node retain], self);
82 VERIFY_INTEGRITY();
83 }
84
85 - (void)removeNode:(HFAnnotatedTreeNode *)node {
86 HFASSERT(node != nil);
87 HFASSERT(get_parent(node) != nil);
88 delete(node, self);
89 [node release];
90 VERIFY_INTEGRITY();
91 }
92
93 #if ! NDEBUG
94 - (void)verifyIntegrity {
95 [root verifyIntegrity];
96 [root verifyAnnotation:annotater];
97 }
98 #endif
99
100 static HFAnnotatedTreeNode *get_root(HFAnnotatedTree *tree) {
101 return tree->root;
102 }
103
104 static HFAnnotatedTreeAnnotaterFunction_t get_annotater(HFAnnotatedTree *tree) {
105 return tree->annotater;
106 }
107
108 @end
109
110 @implementation HFAnnotatedTreeNode
111
112 - (void)dealloc {
113 [left release];
114 [right release];
115 [super dealloc];
116 }
117
118 - (NSComparisonResult)compare:(HFAnnotatedTreeNode *)node {
119 USE(node);
120 UNIMPLEMENTED();
121 }
122
123 - (id)nextNode {
124 return next_node(self);
125 }
126
127 - (id)leftNode { return left; }
128 - (id)rightNode { return right; }
129 - (id)parentNode { return parent; }
130
131 - (id)mutableCopyWithZone:(NSZone *)zone {
132 HFAnnotatedTreeNode *copied = [[[self class] alloc] init];
133 if (left) {
134 copied->left = [left mutableCopyWithZone:zone];
135 copied->left->parent = copied;
136 }
137 if (right) {
138 copied->right = [right mutableCopyWithZone:zone];
139 copied->right->parent = copied;
140 }
141 copied->level = level;
142 copied->annotation = annotation;
143 return copied;
144 }
145
146 static HFAnnotatedTreeNode *left_child(HFAnnotatedTreeNode *node) {
147 return node->left;
148 }
149
150 static HFAnnotatedTreeNode *right_child(HFAnnotatedTreeNode *node) {
151 return node->right;
152 }
153
154
155 static HFAnnotatedTreeNode *create_root(void) {
156 HFAnnotatedTreeNode *result = [[HFAnnotatedTreeNode alloc] init];
157 result->level = UINT_MAX; //the root has a huge level
158 return result;
159 }
160
161 static void reannotate(HFAnnotatedTreeNode *node, HFAnnotatedTree *tree) {
162 HFASSERT(node != nil);
163 HFASSERT(tree != nil);
164 const HFAnnotatedTreeAnnotaterFunction_t annotater = get_annotater(tree);
165 node->annotation = annotater(node->left, node->right);
166 }
167
168 static void insert(HFAnnotatedTreeNode *root, HFAnnotatedTreeNode *node, HFAnnotatedTree *tree) {
169 /* Insert node at the proper place in the tree. root is the root node, and we always insert to the left of root */
170 BOOL left = YES;
171 HFAnnotatedTreeNode *parentNode = root, *currentChild;
172 /* Descend the tree until we find where to insert */
173 while ((currentChild = (left ? parentNode->left : parentNode->right)) != nil) {
174 parentNode = currentChild;
175 left = ([parentNode compare:node] >= 0); //if parentNode is larger than the child, then the child goes to the left of node
176 }
177
178 /* Now insert, potentially unbalancing the tree */
179 if (left) {
180 parentNode->left = node;
181 }
182 else {
183 parentNode->right = node;
184 }
185
186 /* Tell our node about its new parent */
187 node->parent = parentNode;
188
189 /* Rebalance and update annotations */
190 rebalanceAfterLeafAdd(node, tree);
191 }
192
193 static void skew(HFAnnotatedTreeNode *oldparent, HFAnnotatedTree *tree) {
194 HFAnnotatedTreeNode *newp = oldparent->left;
195
196 if (oldparent->parent->left == oldparent) {
197 /* oldparent is the left child of its parent. Substitute in our left child. */
198 oldparent->parent->left = newp;
199 }
200 else {
201 /* oldparent is the right child of its parent. Substitute in our left child. */
202 oldparent->parent->right = newp;
203 }
204
205 /* Tell the child about its new parent */
206 newp->parent = oldparent->parent;
207
208 /* Adopt its right child as our left child, and tell it about its new parent */
209 oldparent->left = newp->right;
210 if (oldparent->left) oldparent->left->parent = oldparent;
211
212 /* We are now the right child of the new parent */
213 newp->right = oldparent;
214 oldparent->parent = newp;
215
216 /* If we're now a leaf, our level is 1. Otherwise, it's one more than the level of our child. */
217 oldparent->level = oldparent->left ? oldparent->left->level + 1 : 1;
218
219 /* oldparent and newp both had their children changed, so need to be reannotated */
220 reannotate(oldparent, tree);
221 reannotate(newp, tree);
222 }
223
224 static BOOL split(HFAnnotatedTreeNode *oldparent, HFAnnotatedTree *tree) {
225 HFAnnotatedTreeNode *newp = oldparent->right;
226 if (newp && newp->right && newp->right->level == oldparent->level) {
227 if (oldparent->parent->left == oldparent) oldparent->parent->left = newp;
228 else oldparent->parent->right = newp;
229 newp->parent = oldparent->parent;
230 oldparent->parent = newp;
231
232 oldparent->right = newp->left;
233 if (oldparent->right) oldparent->right->parent = oldparent;
234 newp->left = oldparent;
235 newp->level = oldparent->level + 1;
236
237 /* oldparent and newp both had their children changed, so need to be reannotated */
238 reannotate(oldparent, tree);
239 reannotate(newp, tree);
240
241 return YES;
242 }
243 return NO;
244 }
245
246 static void rebalanceAfterLeafAdd(HFAnnotatedTreeNode *node, HFAnnotatedTree *tree) { // n is a node that has just been inserted and is now a leaf node.
247 node->level = 1;
248 node->left = nil;
249 node->right = nil;
250 reannotate(node, tree);
251 HFAnnotatedTreeNode * const root = get_root(tree);
252 HFAnnotatedTreeNode *probe;
253 for (probe = node->parent; probe != root; probe = probe->parent) {
254 reannotate(probe, tree);
255 // At this point probe->parent->level == probe->level
256 if (probe->level != (probe->left ? probe->left->level + 1 : 1)) {
257 // At this point the tree is correct, except (AA2) for n->parent
258 skew(probe, tree);
259 // We handle it (a left add) by changing it into a right add using Skew
260 // If the original add was to the left side of a node that is on the
261 // right side of a horisontal link, probe now points to the rights side
262 // of the second horisontal link, which is correct.
263
264 // However if the original add was to the left of node with a horizontal
265 // link, we must get to the right side of the second link.
266 if (!probe->right || probe->level != probe->right->level) probe = probe->parent;
267 }
268 if (! split(probe->parent, tree)) break;
269 }
270 while (probe) {
271 reannotate(probe, tree);
272 probe = probe->parent;
273 }
274 }
275
276 static void delete(HFAnnotatedTreeNode *n, HFAnnotatedTree *tree) { // If n is not a leaf, we first swap it out with the leaf node that just
277 // precedes it.
278 HFAnnotatedTreeNode *leaf = n, *tmp;
279
280 if (n->left) {
281 /* Descend the right subtree of our left child, to get the closest predecessor */
282 for (leaf = n->left; leaf->right; leaf = leaf->right) {}
283 // When we stop, leaf has no 'right' child so it cannot have a left one
284 }
285 else if (n->right) {
286 /* We have no children that precede us, but we have a child after us, so use our closest successor */
287 leaf = n->right;
288 }
289
290 /* tmp is either the parent who loses the child, or tmp is our right subtree. Either way, we will have to reduce its level. */
291 tmp = leaf->parent == n ? leaf : leaf->parent;
292
293 /* Tell leaf's parent to forget about leaf */
294 if (leaf->parent->left == leaf) {
295 leaf->parent->left = NULL;
296 }
297 else {
298 leaf->parent->right = NULL;
299 }
300 reannotate(leaf->parent, tree);
301
302 if (n != leaf) {
303 /* Replace ourself as our parent's child with leaf */
304 if (n->parent->left == n) n->parent->left = leaf;
305 else n->parent->right = leaf;
306
307 /* Leaf's parent is our parent */
308 leaf->parent = n->parent;
309
310 /* Our left and right children are now leaf's left and right children */
311 if (n->left) n->left->parent = leaf;
312 leaf->left = n->left;
313 if (n->right) n->right->parent = leaf;
314 leaf->right = n->right;
315
316 /* Leaf's level is our level */
317 leaf->level = n->level;
318 }
319 /* Since we adopted n's children, transferring the retain, tell n to forget about them so it doesn't release them */
320 n->left = nil;
321 n->right = nil;
322
323 // free (n);
324
325 HFAnnotatedTreeNode * const root = get_root(tree);
326 while (tmp != root) {
327 reannotate(tmp, tree);
328 // One of tmp's childern had its level reduced
329 if (tmp->level > (tmp->left ? tmp->left->level + 1 : 1)) { // AA2 failed
330 tmp->level--;
331 if (split(tmp, tree)) {
332 if (split(tmp, tree)) skew(tmp->parent->parent, tree);
333 break;
334 }
335 tmp = tmp->parent;
336 }
337 else if (tmp->level <= (tmp->right ? tmp->right->level + 1 : 1)){
338 break;
339 }
340 else { // AA3 failed
341 skew(tmp, tree);
342 //if (tmp->right) tmp->right->level = tmp->right->left ? tmp->right->left->level + 1 : 1;
343 if (tmp->level > tmp->parent->level) {
344 skew(tmp, tree);
345 split(tmp->parent->parent, tree);
346 break;
347 }
348 tmp = tmp->parent->parent;
349 }
350 }
351 while (tmp) {
352 reannotate(tmp, tree);
353 tmp = tmp->parent;
354 }
355 }
356
357 static HFAnnotatedTreeNode *next_node(HFAnnotatedTreeNode *node) {
358 /* Return the next in-order node */
359 HFAnnotatedTreeNode *result;
360 if (node->right) {
361 /* We have a right child, which is after us. Descend its left subtree. */
362 result = node->right;
363 while (result->left) {
364 result = result->left;
365 }
366 }
367 else {
368 /* We have no right child. If we are our parent's left child, then our parent is after us. Otherwise, we're our parent's right child and it was before us, so ascend while we're the parent's right child. */
369 result = node;
370 while (result->parent && result->parent->right == result) {
371 result = result->parent;
372 }
373 /* Now result is the left child of the parent (or has NULL parents), so its parent is the next node */
374 result = result->parent;
375 }
376 /* Don't return the root */
377 if (result != nil && result->parent == nil) {
378 result = next_node(result);
379 }
380 return result;
381 }
382
383 static HFAnnotatedTreeNode *first_node(HFAnnotatedTreeNode *node) {
384 /* Return the first node */
385 HFAnnotatedTreeNode *result = nil, *cursor = node->left;
386 while (cursor) {
387 /* Descend the left subtree */
388 result = cursor;
389 cursor = cursor->left;
390 }
391 return result;
392 }
393
394 static HFAnnotatedTreeNode *get_parent(HFAnnotatedTreeNode *node) {
395 HFASSERT(node != nil);
396 return node->parent;
397 }
398
399 static void __attribute__((unused))verify_integrity(HFAnnotatedTreeNode *n) {
400 HFASSERT(!n->left || n->left->parent == n);
401 HFASSERT(!n->right || n->right->parent == n);
402 HFASSERT(!next_node(n) || [n compare:next_node(n)] <= 0);
403 HFASSERT(!n->parent || n->parent->level >= n->level);
404 if (n->parent == nil) {
405 /* root node */
406 HFASSERT(n->level == UINT_MAX);
407 }
408 else {
409 /* non-root node */
410 HFASSERT(n->level == (n->left == NULL ? 1 : n->left->level + 1));
411 HFASSERT((n->level <= 1) || (n->right && n->level - n->right->level <= 1));
412 }
413 HFASSERT(!n->parent || !n->parent->parent ||
414 n->parent->parent->level > n->level);
415 }
416
417 #if ! NDEBUG
418 - (void)verifyIntegrity {
419 [left verifyIntegrity];
420 [right verifyIntegrity];
421 verify_integrity(self);
422 }
423
424 - (void)verifyAnnotation:(HFAnnotatedTreeAnnotaterFunction_t)annotater {
425 [left verifyAnnotation:annotater];
426 [right verifyAnnotation:annotater];
427 unsigned long long expectedAnnotation = annotater(left, right);
428 HFASSERT(annotation == expectedAnnotation);
429 }
430 #endif
431
432 @end
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.