blob: b61820f9844f35634fe7c1aee299b49c3a9c4e77 [file] [log] [blame]
njne1b2b962005-08-14 22:13:00 +00001
2/*--------------------------------------------------------------------*/
3/*--- An ordered set implemented using an AVL tree. m_oset.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
sewardj9ebd6e02007-01-08 06:01:59 +000010 Copyright (C) 2005-2007 Nicholas Nethercote
njne1b2b962005-08-14 22:13:00 +000011 njn@valgrind.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
31//----------------------------------------------------------------------
32// This file is based on:
33//
34// ANSI C Library for maintainance of AVL Balanced Trees
35// (C) 2000 Daniel Nagy, Budapest University of Technology and Economics
36// Released under GNU General Public License (GPL) version 2
37//----------------------------------------------------------------------
38
39// This file implements a generic ordered set using an AVL tree.
40//
41// Each node in the tree has two parts.
42// - First is the AVL metadata, which is three words: a left pointer, a
43// right pointer, and a word containing balancing information and a
44// "magic" value which provides some checking that the user has not
njna527a492005-12-16 17:06:37 +000045// corrupted the metadata. So the overhead is 12 bytes on 32-bit
46// platforms and 24 bytes on 64-bit platforms.
njne1b2b962005-08-14 22:13:00 +000047// - Second is the user's data. This can be anything. Note that because it
48// comes after the metadata, it will only be word-aligned, even if the
49// user data is a struct that would normally be doubleword-aligned.
50//
51// AvlNode* node -> +---------------+ V
52// | struct |
53// | AvlNode |
54// void* element -> +---------------+ ^
55// | element | |
56// keyOff -> | key | elemSize
57// +---------------+ v
58//
njne2a9ad32007-09-17 05:30:48 +000059// Users have to allocate AvlNodes with OSetGen_AllocNode(), which allocates
njne1b2b962005-08-14 22:13:00 +000060// space for the metadata.
61//
62// The terminology used throughout this file:
63// - a "node", usually called "n", is a pointer to the metadata.
64// - an "element", usually called "e", is a pointer to the user data.
65// - a "key", usually called "k", is a pointer to a key.
66//
67// The helper functions elem_of_node and node_of_elem do the pointer
68// arithmetic to switch between the node and the element. The node magic is
69// checked after each operation to make sure that we're really operating on
70// an AvlNode.
71//
72// Each tree also has an iterator. Note that we cannot use the iterator
njne2a9ad32007-09-17 05:30:48 +000073// internally within this file (eg. we could implement OSetGen_Size() by
njne1b2b962005-08-14 22:13:00 +000074// stepping through with the iterator and counting nodes) because it's
75// non-reentrant -- the user might be using it themselves, and the
76// concurrent uses would screw things up.
77
78#include "pub_core_basics.h"
79#include "pub_core_libcbase.h"
80#include "pub_core_libcassert.h"
81#include "pub_core_libcprint.h"
82#include "pub_core_oset.h"
83
84/*--------------------------------------------------------------------*/
85/*--- Types and constants ---*/
86/*--------------------------------------------------------------------*/
87
njne2a9ad32007-09-17 05:30:48 +000088typedef struct _OSetNode OSetNode;
89
njne1b2b962005-08-14 22:13:00 +000090// Internal names for the OSet types.
91typedef OSet AvlTree;
92typedef OSetNode AvlNode;
93
94// The padding ensures that magic is right at the end of the node,
95// regardless of the machine's word size, so that any overwrites will be
96// detected earlier.
97struct _OSetNode {
98 AvlNode* left;
99 AvlNode* right;
100 Char balance;
njn851ba8d2006-02-24 10:36:54 +0000101 Char padding[sizeof(void*)-sizeof(Char)-sizeof(Short)];
njne1b2b962005-08-14 22:13:00 +0000102 Short magic;
103};
104
105#define STACK_MAX 32 // At most 2**32 entries can be iterated over
106#define OSET_MAGIC 0x5b1f
107
108// An OSet (AVL tree). If cmp is NULL, the key must be a UWord, and must
109// be the first word in the element. If cmp is set, arbitrary keys in
110// arbitrary positions can be used.
111struct _OSet {
112 SizeT keyOff; // key offset
113 OSetCmp_t cmp; // compare a key and an element, or NULL
114 OSetAlloc_t alloc; // allocator
115 OSetFree_t free; // deallocator
116 Int nElems; // number of elements in the tree
117 AvlNode* root; // root node
118
119 AvlNode* nodeStack[STACK_MAX]; // Iterator node stack
120 Int numStack[STACK_MAX]; // Iterator num stack
121 Int stackTop; // Iterator stack pointer, one past end
122};
123
124/*--------------------------------------------------------------------*/
125/*--- Helper operations ---*/
126/*--------------------------------------------------------------------*/
127
128// Given a pointer to the node's element, return the pointer to the AvlNode
129// structure. If the node has a bad magic number, it will die with an
130// assertion failure.
131static inline
132AvlNode* node_of_elem(const void *elem)
133{
134 AvlNode* n = (AvlNode*)((Addr)elem - sizeof(AvlNode));
135 vg_assert2(n->magic == OSET_MAGIC,
136 "bad magic on node %p = %x (expected %x)\n"
137 "possible causes:\n"
njne2a9ad32007-09-17 05:30:48 +0000138 " - node not allocated with VG_(OSetGen_AllocNode)()?\n"
njne1b2b962005-08-14 22:13:00 +0000139 " - node metadata corrupted by underwriting start of element?\n",
140 n, n->magic, OSET_MAGIC);
141 return n;
142}
143
144// Given an AvlNode, return the pointer to the element.
145static inline
146void* elem_of_node(const AvlNode *n)
147{
148 vg_assert2(n->magic == OSET_MAGIC,
149 "bad magic on node %p = %x (expected %x)\n"
150 "possible causes:\n"
151 " - node metadata corrupted by overwriting end of element?\n",
152 n, n->magic, OSET_MAGIC);
153 return (void*)((Addr)n + sizeof(AvlNode));
154}
155
156// Like elem_of_node, but no magic checking.
157static inline
158void* elem_of_node_no_check(const AvlNode *n)
159{
160 return (void*)((Addr)n + sizeof(AvlNode));
161}
162
163static inline
164void* slow_key_of_node(AvlTree* t, AvlNode* n)
165{
166 return (void*)((Addr)elem_of_node(n) + t->keyOff);
167}
168
169static inline
170void* fast_key_of_node(AvlNode* n)
171{
172 return elem_of_node(n);
173}
174
175// Compare the first word of each element. Inlining is *crucial*.
njnafa12262005-12-24 03:10:56 +0000176static inline Word fast_cmp(void* k, AvlNode* n)
njne1b2b962005-08-14 22:13:00 +0000177{
njnafa12262005-12-24 03:10:56 +0000178 return ( *(Word*)k - *(Word*)elem_of_node(n) );
njne1b2b962005-08-14 22:13:00 +0000179}
180
181// Compare a key and an element. Inlining is *crucial*.
njnafa12262005-12-24 03:10:56 +0000182static inline Word slow_cmp(AvlTree* t, void* k, AvlNode* n)
njne1b2b962005-08-14 22:13:00 +0000183{
184 return t->cmp(k, elem_of_node(n));
185}
186
187
188// Swing to the left. Warning: no balance maintainance.
189static void avl_swl ( AvlNode** root )
190{
191 AvlNode* a = *root;
192 AvlNode* b = a->right;
193 *root = b;
194 a->right = b->left;
195 b->left = a;
196}
197
198// Swing to the right. Warning: no balance maintainance.
199static void avl_swr ( AvlNode** root )
200{
201 AvlNode* a = *root;
202 AvlNode* b = a->left;
203 *root = b;
204 a->left = b->right;
205 b->right = a;
206}
207
208// Balance maintainance after especially nasty swings.
209static void avl_nasty ( AvlNode* root )
210{
211 switch (root->balance) {
212 case -1:
213 root->left->balance = 0;
214 root->right->balance = 1;
215 break;
216 case 1:
217 root->left->balance =-1;
218 root->right->balance = 0;
219 break;
220 case 0:
221 root->left->balance = 0;
222 root->right->balance = 0;
223 }
224 root->balance = 0;
225}
226
227
228// Clear the iterator stack.
229static void stackClear(AvlTree* t)
230{
231 Int i;
232 vg_assert(t);
233 for (i = 0; i < STACK_MAX; i++) {
234 t->nodeStack[i] = NULL;
235 t->numStack[i] = 0;
236 }
237 t->stackTop = 0;
238}
239
240// Push onto the iterator stack.
sewardjdff46d52006-10-17 01:40:33 +0000241static inline void stackPush(AvlTree* t, AvlNode* n, Int i)
njne1b2b962005-08-14 22:13:00 +0000242{
243 vg_assert(t->stackTop < STACK_MAX);
244 vg_assert(1 <= i && i <= 3);
245 t->nodeStack[t->stackTop] = n;
246 t-> numStack[t->stackTop] = i;
247 t->stackTop++;
248}
249
250// Pop from the iterator stack.
sewardjdff46d52006-10-17 01:40:33 +0000251static inline Bool stackPop(AvlTree* t, AvlNode** n, Int* i)
njne1b2b962005-08-14 22:13:00 +0000252{
253 vg_assert(t->stackTop <= STACK_MAX);
254
255 if (t->stackTop > 0) {
256 t->stackTop--;
257 *n = t->nodeStack[t->stackTop];
258 *i = t-> numStack[t->stackTop];
259 vg_assert(1 <= *i && *i <= 3);
260 t->nodeStack[t->stackTop] = NULL;
261 t-> numStack[t->stackTop] = 0;
262 return True;
263 } else {
264 return False;
265 }
266}
267
268/*--------------------------------------------------------------------*/
269/*--- Creating and destroying AvlTrees and AvlNodes ---*/
270/*--------------------------------------------------------------------*/
271
272// The underscores avoid GCC complaints about overshadowing global names.
njne2a9ad32007-09-17 05:30:48 +0000273AvlTree* VG_(OSetGen_Create)(OffT _keyOff, OSetCmp_t _cmp,
274 OSetAlloc_t _alloc, OSetFree_t _free)
njne1b2b962005-08-14 22:13:00 +0000275{
276 AvlTree* t;
277
278 // Check the padding is right and the AvlNode is the expected size.
279 vg_assert(sizeof(AvlNode) == 3*sizeof(void*));
280
281 // Sanity check args
282 vg_assert(_alloc);
283 vg_assert(_free);
284 if (!_cmp) vg_assert(0 == _keyOff); // If no cmp, offset must be zero
285
286 t = _alloc(sizeof(AvlTree));
287 t->keyOff = _keyOff;
288 t->cmp = _cmp;
289 t->alloc = _alloc;
290 t->free = _free;
291 t->nElems = 0;
292 t->root = NULL;
293 stackClear(t);
294
295 return t;
296}
297
njne2a9ad32007-09-17 05:30:48 +0000298AvlTree* VG_(OSetWord_Create)(OSetAlloc_t _alloc, OSetFree_t _free)
299{
300 return VG_(OSetGen_Create)(/*keyOff*/0, /*cmp*/NULL, _alloc, _free);
301}
302
njne1b2b962005-08-14 22:13:00 +0000303// Destructor, frees up all memory held by remaining nodes.
njne2a9ad32007-09-17 05:30:48 +0000304void VG_(OSetGen_Destroy)(AvlTree* t)
njne1b2b962005-08-14 22:13:00 +0000305{
sewardjdff46d52006-10-17 01:40:33 +0000306 AvlNode* n = NULL;
307 Int i = 0, sz = 0;
njne1b2b962005-08-14 22:13:00 +0000308
309 vg_assert(t);
310 stackClear(t);
311 if (t->root)
312 stackPush(t, t->root, 1);
313
njne2a9ad32007-09-17 05:30:48 +0000314 /* Free all the AvlNodes. This is a post-order traversal, because we */
315 /* must free all children of a node before the node itself. */
njne1b2b962005-08-14 22:13:00 +0000316 while (stackPop(t, &n, &i)) {
317 switch (i) {
318 case 1:
319 stackPush(t, n, 2);
320 if (n->left) stackPush(t, n->left, 1);
321 break;
322 case 2:
323 stackPush(t, n, 3);
324 if (n->right) stackPush(t, n->right, 1);
325 break;
326 case 3:
327 t->free(n);
328 sz++;
329 break;
330 }
331 }
332 vg_assert(sz == t->nElems);
333
njne2a9ad32007-09-17 05:30:48 +0000334 /* Free the AvlTree itself. */
njne1b2b962005-08-14 22:13:00 +0000335 t->free(t);
336}
337
njne2a9ad32007-09-17 05:30:48 +0000338void VG_(OSetWord_Destroy)(AvlTree* t)
339{
340 VG_(OSetGen_Destroy)(t);
341}
342
njne1b2b962005-08-14 22:13:00 +0000343// Allocate and initialise a new node.
njne2a9ad32007-09-17 05:30:48 +0000344void* VG_(OSetGen_AllocNode)(AvlTree* t, SizeT elemSize)
njne1b2b962005-08-14 22:13:00 +0000345{
346 Int nodeSize = sizeof(AvlNode) + elemSize;
347 AvlNode* n = t->alloc( nodeSize );
348 vg_assert(elemSize > 0);
349 VG_(memset)(n, 0, nodeSize);
350 n->magic = OSET_MAGIC;
351 return elem_of_node(n);
352}
353
njne2a9ad32007-09-17 05:30:48 +0000354void VG_(OSetGen_FreeNode)(AvlTree* t, void* e)
njne1b2b962005-08-14 22:13:00 +0000355{
356 t->free( node_of_elem(e) );
357}
358
359/*--------------------------------------------------------------------*/
360/*--- Insertion ---*/
361/*--------------------------------------------------------------------*/
362
njnafa12262005-12-24 03:10:56 +0000363static inline Word cmp_key_root(AvlTree* t, AvlNode* n)
njne1b2b962005-08-14 22:13:00 +0000364{
365 return t->cmp
366 ? slow_cmp(t, slow_key_of_node(t, n), t->root)
367 : fast_cmp( fast_key_of_node( n), t->root);
368}
369
370// Insert element e into the non-empty AVL tree t.
371// Returns True if the depth of the tree has grown.
372static Bool avl_insert(AvlTree* t, AvlNode* n)
373{
njnafa12262005-12-24 03:10:56 +0000374 Word cmpres = cmp_key_root(t, n);
njne1b2b962005-08-14 22:13:00 +0000375
376 if (cmpres < 0) {
377 // Insert into the left subtree.
378 if (t->root->left) {
379 // Only need to set the used fields in the subtree.
380 AvlTree left_subtree;
381 left_subtree.root = t->root->left;
382 left_subtree.cmp = t->cmp;
383 left_subtree.keyOff = t->keyOff;
384 if (avl_insert(&left_subtree, n)) {
385 switch (t->root->balance--) {
386 case 1: return False;
387 case 0: return True;
388 }
389 if (t->root->left->balance < 0) {
390 avl_swr(&(t->root));
391 t->root->balance = 0;
392 t->root->right->balance = 0;
393 } else {
394 avl_swl(&(t->root->left));
395 avl_swr(&(t->root));
396 avl_nasty(t->root);
397 }
398 } else {
399 t->root->left=left_subtree.root;
400 }
401 return False;
402 } else {
403 t->root->left = n;
404 if (t->root->balance--) return False;
405 return True;
406 }
407
408 } else if (cmpres > 0) {
409 // Insert into the right subtree
410 if (t->root->right) {
411 // Only need to set the used fields in the subtree.
412 AvlTree right_subtree;
413 right_subtree.root = t->root->right;
414 right_subtree.cmp = t->cmp;
415 right_subtree.keyOff = t->keyOff;
416 if (avl_insert(&right_subtree, n)) {
417 switch (t->root->balance++) {
418 case -1: return False;
419 case 0: return True;
420 }
421 if (t->root->right->balance > 0) {
422 avl_swl(&(t->root));
423 t->root->balance = 0;
424 t->root->left->balance = 0;
425 } else {
426 avl_swr(&(t->root->right));
427 avl_swl(&(t->root));
428 avl_nasty(t->root);
429 }
430 } else {
431 t->root->right=right_subtree.root;
432 }
433 return False;
434 } else {
435 t->root->right = n;
436 if (t->root->balance++) return False;
437 return True;
438 }
439
440 } else {
njne2a9ad32007-09-17 05:30:48 +0000441 vg_assert2(0, "OSet{Word,Gen}_Insert: duplicate element added");
njne1b2b962005-08-14 22:13:00 +0000442 }
443}
444
445// Insert element e into the AVL tree t. This is just a wrapper for
446// avl_insert() which doesn't return a Bool.
njne2a9ad32007-09-17 05:30:48 +0000447void VG_(OSetGen_Insert)(AvlTree* t, void* e)
njne1b2b962005-08-14 22:13:00 +0000448{
tom60a4b0b2005-10-12 10:45:27 +0000449 AvlNode* n;
450
njne1b2b962005-08-14 22:13:00 +0000451 vg_assert(t);
452
njne2a9ad32007-09-17 05:30:48 +0000453 // Initialise. Even though OSetGen_AllocNode zeroes these fields, we should
njne1b2b962005-08-14 22:13:00 +0000454 // do it again in case a node is removed and then re-added to the tree.
tom60a4b0b2005-10-12 10:45:27 +0000455 n = node_of_elem(e);
njne1b2b962005-08-14 22:13:00 +0000456 n->left = 0;
457 n->right = 0;
458 n->balance = 0;
459
460 // Insert into an empty tree
461 if (!t->root) {
462 t->root = n;
463 } else {
464 avl_insert(t, n);
465 }
466
467 t->nElems++;
468 t->stackTop = 0; // So the iterator can't get out of sync
469}
470
njne2a9ad32007-09-17 05:30:48 +0000471void VG_(OSetWord_Insert)(AvlTree* t, Word val)
472{
473 Word* node = VG_(OSetGen_AllocNode)(t, sizeof(Word));
474 *node = val;
475 VG_(OSetGen_Insert)(t, node);
476}
477
njne1b2b962005-08-14 22:13:00 +0000478/*--------------------------------------------------------------------*/
479/*--- Lookup ---*/
480/*--------------------------------------------------------------------*/
481
482// Find the *node* in t matching k, or NULL if not found.
483static AvlNode* avl_lookup(AvlTree* t, void* k)
484{
njnafa12262005-12-24 03:10:56 +0000485 Word cmpres;
njn0684dd42005-08-15 02:05:21 +0000486 AvlNode* curr = t->root;
njne1b2b962005-08-14 22:13:00 +0000487
488 if (t->cmp) {
489 // General case
490 while (True) {
491 if (curr == NULL) return NULL;
492 cmpres = slow_cmp(t, k, curr);
493 if (cmpres < 0) curr = curr->left; else
494 if (cmpres > 0) curr = curr->right; else
495 return curr;
496 }
497 } else {
498 // Fast-track special case. We use the no-check version of
499 // elem_of_node because it saves about 10% on lookup time. This
500 // shouldn't be very dangerous because each node will have been
501 // checked on insertion.
njnafa12262005-12-24 03:10:56 +0000502 Word kk = *(Word*)k;
njne1b2b962005-08-14 22:13:00 +0000503 while (True) {
504 if (curr == NULL) return NULL;
njnafa12262005-12-24 03:10:56 +0000505 cmpres = kk - *(Word*)elem_of_node_no_check(curr);
njne1b2b962005-08-14 22:13:00 +0000506 if (cmpres < 0) curr = curr->left; else
507 if (cmpres > 0) curr = curr->right; else
508 return curr;
509 }
510 }
511}
512
513// Find the *element* in t matching k, or NULL if not found.
njne2a9ad32007-09-17 05:30:48 +0000514void* VG_(OSetGen_Lookup)(AvlTree* t, void* k)
njne1b2b962005-08-14 22:13:00 +0000515{
njn0684dd42005-08-15 02:05:21 +0000516 AvlNode* n;
517 vg_assert(t);
518 n = avl_lookup(t, k);
njne1b2b962005-08-14 22:13:00 +0000519 return ( n ? elem_of_node(n) : NULL );
520}
521
njnaa260e82005-08-17 21:06:07 +0000522// Find the *element* in t matching k, or NULL if not found; use the given
523// comparison function rather than the standard one.
njne2a9ad32007-09-17 05:30:48 +0000524void* VG_(OSetGen_LookupWithCmp)(AvlTree* t, void* k, OSetCmp_t cmp)
njnaa260e82005-08-17 21:06:07 +0000525{
526 // Save the normal one to the side, then restore once we're done.
527 void* e;
528 OSetCmp_t tmpcmp;
529 vg_assert(t);
530 tmpcmp = t->cmp;
531 t->cmp = cmp;
njne2a9ad32007-09-17 05:30:48 +0000532 e = VG_(OSetGen_Lookup)(t, k);
njnaa260e82005-08-17 21:06:07 +0000533 t->cmp = tmpcmp;
534 return e;
535}
536
njne1b2b962005-08-14 22:13:00 +0000537// Is there an element matching k?
njne2a9ad32007-09-17 05:30:48 +0000538Bool VG_(OSetGen_Contains)(AvlTree* t, void* k)
njne1b2b962005-08-14 22:13:00 +0000539{
njne2a9ad32007-09-17 05:30:48 +0000540 return (NULL != VG_(OSetGen_Lookup)(t, k));
541}
542
543Bool VG_(OSetWord_Contains)(AvlTree* t, Word val)
544{
545 return (NULL != VG_(OSetGen_Lookup)(t, &val));
njne1b2b962005-08-14 22:13:00 +0000546}
547
548/*--------------------------------------------------------------------*/
549/*--- Deletion ---*/
550/*--------------------------------------------------------------------*/
551
552static Bool avl_removeroot(AvlTree* t);
553
554// Remove an already-selected node n from the AVL tree t.
555// Returns True if the depth of the tree has shrunk.
556static Bool avl_remove(AvlTree* t, AvlNode* n)
557{
558 Bool ch;
njnafa12262005-12-24 03:10:56 +0000559 Word cmpres = cmp_key_root(t, n);
njne1b2b962005-08-14 22:13:00 +0000560
561 if (cmpres < 0) {
tom60a4b0b2005-10-12 10:45:27 +0000562 AvlTree left_subtree;
njne1b2b962005-08-14 22:13:00 +0000563 // Remove from the left subtree
564 vg_assert(t->root->left);
njne1b2b962005-08-14 22:13:00 +0000565 // Only need to set the used fields in the subtree.
566 left_subtree.root = t->root->left;
567 left_subtree.cmp = t->cmp;
568 left_subtree.keyOff = t->keyOff;
569 ch = avl_remove(&left_subtree, n);
570 t->root->left = left_subtree.root;
571 if (ch) {
572 switch (t->root->balance++) {
573 case -1: return True;
574 case 0: return False;
575 }
576 switch (t->root->right->balance) {
577 case 0:
578 avl_swl(&(t->root));
579 t->root->balance = -1;
580 t->root->left->balance = 1;
581 return False;
582 case 1:
583 avl_swl(&(t->root));
584 t->root->balance = 0;
585 t->root->left->balance = 0;
586 return True;
587 }
588 avl_swr(&(t->root->right));
589 avl_swl(&(t->root));
590 avl_nasty(t->root);
591 return True;
592 } else {
593 return False;
594 }
595
596 } else if (cmpres > 0) {
597 // Remove from the right subtree
598 AvlTree right_subtree;
599 vg_assert(t->root->right);
600 // Only need to set the used fields in the subtree.
601 right_subtree.root = t->root->right;
602 right_subtree.cmp = t->cmp;
603 right_subtree.keyOff = t->keyOff;
604 ch = avl_remove(&right_subtree, n);
605 t->root->right = right_subtree.root;
606 if (ch) {
607 switch (t->root->balance--) {
608 case 1: return True;
609 case 0: return False;
610 }
611 switch (t->root->left->balance) {
612 case 0:
613 avl_swr(&(t->root));
614 t->root->balance = 1;
615 t->root->right->balance = -1;
616 return False;
617 case -1:
618 avl_swr(&(t->root));
619 t->root->balance = 0;
620 t->root->right->balance = 0;
621 return True;
622 }
623 avl_swl(&(t->root->left));
624 avl_swr(&(t->root));
625 avl_nasty(t->root);
626 return True;
627 } else {
628 return False;
629 }
630
631 } else {
632 // Found the node to be removed.
633 vg_assert(t->root == n);
634 return avl_removeroot(t);
635 }
636}
637
638// Remove the root of the AVL tree t.
639// Returns True if the depth of the tree has shrunk.
640static Bool avl_removeroot(AvlTree* t)
641{
njnafa12262005-12-24 03:10:56 +0000642 Bool ch;
njne1b2b962005-08-14 22:13:00 +0000643 AvlNode* n;
644
njne1b2b962005-08-14 22:13:00 +0000645 if (!t->root->left) {
646 if (!t->root->right) {
647 t->root = NULL;
648 return True;
649 }
650 t->root = t->root->right;
651 return True;
652 }
653 if (!t->root->right) {
654 t->root = t->root->left;
655 return True;
656 }
657 if (t->root->balance < 0) {
658 // Remove from the left subtree
659 n = t->root->left;
660 while (n->right) n = n->right;
661 } else {
662 // Remove from the right subtree
663 n = t->root->right;
664 while (n->left) n = n->left;
665 }
666 ch = avl_remove(t, n);
667 n->left = t->root->left;
668 n->right = t->root->right;
669 n->balance = t->root->balance;
670 t->root = n;
671 if (n->balance == 0) return ch;
672 return False;
673}
674
675// Remove and return the element matching the key 'k', or NULL if not present.
njne2a9ad32007-09-17 05:30:48 +0000676void* VG_(OSetGen_Remove)(AvlTree* t, void* k)
njne1b2b962005-08-14 22:13:00 +0000677{
678 // Have to find the node first, then remove it.
679 AvlNode* n = avl_lookup(t, k);
680 if (n) {
681 avl_remove(t, n);
682 t->nElems--;
683 t->stackTop = 0; // So the iterator can't get out of sync
684 return elem_of_node(n);
685 } else {
686 return NULL;
687 }
688}
689
njne2a9ad32007-09-17 05:30:48 +0000690Bool VG_(OSetWord_Remove)(AvlTree* t, Word val)
691{
692 void* n = VG_(OSetGen_Remove)(t, &val);
693 if (n) {
694 VG_(OSetGen_FreeNode)(t, n);
695 return True;
696 } else {
697 return False;
698 }
699}
700
njne1b2b962005-08-14 22:13:00 +0000701/*--------------------------------------------------------------------*/
702/*--- Iterator ---*/
703/*--------------------------------------------------------------------*/
704
705// The iterator is implemented using in-order traversal with an explicit
706// stack, which lets us do the traversal one step at a time and remember
njne2a9ad32007-09-17 05:30:48 +0000707// where we are between each call to OSetGen_Next().
njne1b2b962005-08-14 22:13:00 +0000708
njne2a9ad32007-09-17 05:30:48 +0000709void VG_(OSetGen_ResetIter)(AvlTree* t)
njne1b2b962005-08-14 22:13:00 +0000710{
711 vg_assert(t);
712 stackClear(t);
713 if (t->root)
714 stackPush(t, t->root, 1);
715}
716
njne2a9ad32007-09-17 05:30:48 +0000717void VG_(OSetWord_ResetIter)(AvlTree* t)
718{
719 VG_(OSetGen_ResetIter)(t);
720}
721
722void* VG_(OSetGen_Next)(AvlTree* t)
njne1b2b962005-08-14 22:13:00 +0000723{
sewardjdff46d52006-10-17 01:40:33 +0000724 Int i = 0;
725 OSetNode* n = NULL;
njne1b2b962005-08-14 22:13:00 +0000726
727 vg_assert(t);
728
729 // This in-order traversal requires each node to be pushed and popped
730 // three times. These could be avoided by updating nodes in-situ on the
731 // top of the stack, but the push/pop cost is so small that it's worth
732 // keeping this loop in this simpler form.
733 while (stackPop(t, &n, &i)) {
734 switch (i) {
735 case 1:
736 stackPush(t, n, 2);
737 if (n->left) stackPush(t, n->left, 1);
738 break;
739 case 2:
740 stackPush(t, n, 3);
741 return elem_of_node(n);
742 case 3:
743 if (n->right) stackPush(t, n->right, 1);
744 break;
745 }
746 }
747
748 // Stack empty, iterator is exhausted, return NULL
749 return NULL;
750}
751
njne2a9ad32007-09-17 05:30:48 +0000752Bool VG_(OSetWord_Next)(AvlTree* t, Word* val)
753{
754 Word* n = VG_(OSetGen_Next)(t);
755 if (n) {
756 *val = *n;
757 return True;
758 } else {
759 return False;
760 }
761}
762
njne1b2b962005-08-14 22:13:00 +0000763/*--------------------------------------------------------------------*/
764/*--- Miscellaneous operations ---*/
765/*--------------------------------------------------------------------*/
766
njne2a9ad32007-09-17 05:30:48 +0000767Int VG_(OSetGen_Size)(AvlTree* t)
njne1b2b962005-08-14 22:13:00 +0000768{
769 vg_assert(t);
770 return t->nElems;
771}
772
njne2a9ad32007-09-17 05:30:48 +0000773Int VG_(OSetWord_Size)(AvlTree* t)
774{
775 return VG_(OSetGen_Size)(t);
776}
777
njne1b2b962005-08-14 22:13:00 +0000778static void OSet_Print2( AvlTree* t, AvlNode* n,
779 Char*(*strElem)(void *), Int p )
780{
781 // This is a recursive in-order traversal.
782 Int q = p;
783 if (NULL == n) return;
784 if (n->right) OSet_Print2(t, n->right, strElem, p+1);
785 while (q--) VG_(printf)(".. ");
786 VG_(printf)("%s\n", strElem(elem_of_node(n)));
787 if (n->left) OSet_Print2(t, n->left, strElem, p+1);
788}
789
790__attribute__((unused))
791static void OSet_Print( AvlTree* t, const HChar *where, Char*(*strElem)(void *) )
792{
793 VG_(printf)("-- start %s ----------------\n", where);
794 OSet_Print2(t, t->root, strElem, 0);
795 VG_(printf)("-- end %s ----------------\n", where);
796}
797
798/*--------------------------------------------------------------------*/
799/*--- end ---*/
800/*--------------------------------------------------------------------*/