blob: 63cd25b2efdfb54d45a1334f3b14208053335b27 [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//
59// Users have to allocate AvlNodes with OSet_AllocNode(), which allocates
60// 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
73// internally within this file (eg. we could implement OSet_Size() by
74// 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
88// Internal names for the OSet types.
89typedef OSet AvlTree;
90typedef OSetNode AvlNode;
91
92// The padding ensures that magic is right at the end of the node,
93// regardless of the machine's word size, so that any overwrites will be
94// detected earlier.
95struct _OSetNode {
96 AvlNode* left;
97 AvlNode* right;
98 Char balance;
njn851ba8d2006-02-24 10:36:54 +000099 Char padding[sizeof(void*)-sizeof(Char)-sizeof(Short)];
njne1b2b962005-08-14 22:13:00 +0000100 Short magic;
101};
102
103#define STACK_MAX 32 // At most 2**32 entries can be iterated over
104#define OSET_MAGIC 0x5b1f
105
106// An OSet (AVL tree). If cmp is NULL, the key must be a UWord, and must
107// be the first word in the element. If cmp is set, arbitrary keys in
108// arbitrary positions can be used.
109struct _OSet {
110 SizeT keyOff; // key offset
111 OSetCmp_t cmp; // compare a key and an element, or NULL
112 OSetAlloc_t alloc; // allocator
113 OSetFree_t free; // deallocator
114 Int nElems; // number of elements in the tree
115 AvlNode* root; // root node
116
117 AvlNode* nodeStack[STACK_MAX]; // Iterator node stack
118 Int numStack[STACK_MAX]; // Iterator num stack
119 Int stackTop; // Iterator stack pointer, one past end
120};
121
122/*--------------------------------------------------------------------*/
123/*--- Helper operations ---*/
124/*--------------------------------------------------------------------*/
125
126// Given a pointer to the node's element, return the pointer to the AvlNode
127// structure. If the node has a bad magic number, it will die with an
128// assertion failure.
129static inline
130AvlNode* node_of_elem(const void *elem)
131{
132 AvlNode* n = (AvlNode*)((Addr)elem - sizeof(AvlNode));
133 vg_assert2(n->magic == OSET_MAGIC,
134 "bad magic on node %p = %x (expected %x)\n"
135 "possible causes:\n"
136 " - node not allocated with VG_(OSet_AllocNode)()?\n"
137 " - node metadata corrupted by underwriting start of element?\n",
138 n, n->magic, OSET_MAGIC);
139 return n;
140}
141
142// Given an AvlNode, return the pointer to the element.
143static inline
144void* elem_of_node(const AvlNode *n)
145{
146 vg_assert2(n->magic == OSET_MAGIC,
147 "bad magic on node %p = %x (expected %x)\n"
148 "possible causes:\n"
149 " - node metadata corrupted by overwriting end of element?\n",
150 n, n->magic, OSET_MAGIC);
151 return (void*)((Addr)n + sizeof(AvlNode));
152}
153
154// Like elem_of_node, but no magic checking.
155static inline
156void* elem_of_node_no_check(const AvlNode *n)
157{
158 return (void*)((Addr)n + sizeof(AvlNode));
159}
160
161static inline
162void* slow_key_of_node(AvlTree* t, AvlNode* n)
163{
164 return (void*)((Addr)elem_of_node(n) + t->keyOff);
165}
166
167static inline
168void* fast_key_of_node(AvlNode* n)
169{
170 return elem_of_node(n);
171}
172
173// Compare the first word of each element. Inlining is *crucial*.
njnafa12262005-12-24 03:10:56 +0000174static inline Word fast_cmp(void* k, AvlNode* n)
njne1b2b962005-08-14 22:13:00 +0000175{
njnafa12262005-12-24 03:10:56 +0000176 return ( *(Word*)k - *(Word*)elem_of_node(n) );
njne1b2b962005-08-14 22:13:00 +0000177}
178
179// Compare a key and an element. Inlining is *crucial*.
njnafa12262005-12-24 03:10:56 +0000180static inline Word slow_cmp(AvlTree* t, void* k, AvlNode* n)
njne1b2b962005-08-14 22:13:00 +0000181{
182 return t->cmp(k, elem_of_node(n));
183}
184
185
186// Swing to the left. Warning: no balance maintainance.
187static void avl_swl ( AvlNode** root )
188{
189 AvlNode* a = *root;
190 AvlNode* b = a->right;
191 *root = b;
192 a->right = b->left;
193 b->left = a;
194}
195
196// Swing to the right. Warning: no balance maintainance.
197static void avl_swr ( AvlNode** root )
198{
199 AvlNode* a = *root;
200 AvlNode* b = a->left;
201 *root = b;
202 a->left = b->right;
203 b->right = a;
204}
205
206// Balance maintainance after especially nasty swings.
207static void avl_nasty ( AvlNode* root )
208{
209 switch (root->balance) {
210 case -1:
211 root->left->balance = 0;
212 root->right->balance = 1;
213 break;
214 case 1:
215 root->left->balance =-1;
216 root->right->balance = 0;
217 break;
218 case 0:
219 root->left->balance = 0;
220 root->right->balance = 0;
221 }
222 root->balance = 0;
223}
224
225
226// Clear the iterator stack.
227static void stackClear(AvlTree* t)
228{
229 Int i;
230 vg_assert(t);
231 for (i = 0; i < STACK_MAX; i++) {
232 t->nodeStack[i] = NULL;
233 t->numStack[i] = 0;
234 }
235 t->stackTop = 0;
236}
237
238// Push onto the iterator stack.
sewardjdff46d52006-10-17 01:40:33 +0000239static inline void stackPush(AvlTree* t, AvlNode* n, Int i)
njne1b2b962005-08-14 22:13:00 +0000240{
241 vg_assert(t->stackTop < STACK_MAX);
242 vg_assert(1 <= i && i <= 3);
243 t->nodeStack[t->stackTop] = n;
244 t-> numStack[t->stackTop] = i;
245 t->stackTop++;
246}
247
248// Pop from the iterator stack.
sewardjdff46d52006-10-17 01:40:33 +0000249static inline Bool stackPop(AvlTree* t, AvlNode** n, Int* i)
njne1b2b962005-08-14 22:13:00 +0000250{
251 vg_assert(t->stackTop <= STACK_MAX);
252
253 if (t->stackTop > 0) {
254 t->stackTop--;
255 *n = t->nodeStack[t->stackTop];
256 *i = t-> numStack[t->stackTop];
257 vg_assert(1 <= *i && *i <= 3);
258 t->nodeStack[t->stackTop] = NULL;
259 t-> numStack[t->stackTop] = 0;
260 return True;
261 } else {
262 return False;
263 }
264}
265
266/*--------------------------------------------------------------------*/
267/*--- Creating and destroying AvlTrees and AvlNodes ---*/
268/*--------------------------------------------------------------------*/
269
270// The underscores avoid GCC complaints about overshadowing global names.
271AvlTree* VG_(OSet_Create)(OffT _keyOff, OSetCmp_t _cmp,
272 OSetAlloc_t _alloc, OSetFree_t _free)
273{
274 AvlTree* t;
275
276 // Check the padding is right and the AvlNode is the expected size.
277 vg_assert(sizeof(AvlNode) == 3*sizeof(void*));
278
279 // Sanity check args
280 vg_assert(_alloc);
281 vg_assert(_free);
282 if (!_cmp) vg_assert(0 == _keyOff); // If no cmp, offset must be zero
283
284 t = _alloc(sizeof(AvlTree));
285 t->keyOff = _keyOff;
286 t->cmp = _cmp;
287 t->alloc = _alloc;
288 t->free = _free;
289 t->nElems = 0;
290 t->root = NULL;
291 stackClear(t);
292
293 return t;
294}
295
296// Destructor, frees up all memory held by remaining nodes.
njne004d722005-12-22 06:20:59 +0000297void VG_(OSet_Destroy)(AvlTree* t, OSetNodeDestroy_t destroyNode)
njne1b2b962005-08-14 22:13:00 +0000298{
sewardjdff46d52006-10-17 01:40:33 +0000299 AvlNode* n = NULL;
300 Int i = 0, sz = 0;
njne1b2b962005-08-14 22:13:00 +0000301
302 vg_assert(t);
303 stackClear(t);
304 if (t->root)
305 stackPush(t, t->root, 1);
306
307 // Free all the AvlNodes. This is a post-order traversal, because we
308 // must free all children of a node before the node itself.
309 while (stackPop(t, &n, &i)) {
310 switch (i) {
311 case 1:
312 stackPush(t, n, 2);
313 if (n->left) stackPush(t, n->left, 1);
314 break;
315 case 2:
316 stackPush(t, n, 3);
317 if (n->right) stackPush(t, n->right, 1);
318 break;
319 case 3:
njne004d722005-12-22 06:20:59 +0000320 if (destroyNode) destroyNode(n);
njne1b2b962005-08-14 22:13:00 +0000321 t->free(n);
322 sz++;
323 break;
324 }
325 }
326 vg_assert(sz == t->nElems);
327
328 // Free the AvlTree itself.
329 t->free(t);
330}
331
332// Allocate and initialise a new node.
333void* VG_(OSet_AllocNode)(AvlTree* t, SizeT elemSize)
334{
335 Int nodeSize = sizeof(AvlNode) + elemSize;
336 AvlNode* n = t->alloc( nodeSize );
337 vg_assert(elemSize > 0);
338 VG_(memset)(n, 0, nodeSize);
339 n->magic = OSET_MAGIC;
340 return elem_of_node(n);
341}
342
343void VG_(OSet_FreeNode)(AvlTree* t, void* e)
344{
345 t->free( node_of_elem(e) );
346}
347
348/*--------------------------------------------------------------------*/
349/*--- Insertion ---*/
350/*--------------------------------------------------------------------*/
351
njnafa12262005-12-24 03:10:56 +0000352static inline Word cmp_key_root(AvlTree* t, AvlNode* n)
njne1b2b962005-08-14 22:13:00 +0000353{
354 return t->cmp
355 ? slow_cmp(t, slow_key_of_node(t, n), t->root)
356 : fast_cmp( fast_key_of_node( n), t->root);
357}
358
359// Insert element e into the non-empty AVL tree t.
360// Returns True if the depth of the tree has grown.
361static Bool avl_insert(AvlTree* t, AvlNode* n)
362{
njnafa12262005-12-24 03:10:56 +0000363 Word cmpres = cmp_key_root(t, n);
njne1b2b962005-08-14 22:13:00 +0000364
365 if (cmpres < 0) {
366 // Insert into the left subtree.
367 if (t->root->left) {
368 // Only need to set the used fields in the subtree.
369 AvlTree left_subtree;
370 left_subtree.root = t->root->left;
371 left_subtree.cmp = t->cmp;
372 left_subtree.keyOff = t->keyOff;
373 if (avl_insert(&left_subtree, n)) {
374 switch (t->root->balance--) {
375 case 1: return False;
376 case 0: return True;
377 }
378 if (t->root->left->balance < 0) {
379 avl_swr(&(t->root));
380 t->root->balance = 0;
381 t->root->right->balance = 0;
382 } else {
383 avl_swl(&(t->root->left));
384 avl_swr(&(t->root));
385 avl_nasty(t->root);
386 }
387 } else {
388 t->root->left=left_subtree.root;
389 }
390 return False;
391 } else {
392 t->root->left = n;
393 if (t->root->balance--) return False;
394 return True;
395 }
396
397 } else if (cmpres > 0) {
398 // Insert into the right subtree
399 if (t->root->right) {
400 // Only need to set the used fields in the subtree.
401 AvlTree right_subtree;
402 right_subtree.root = t->root->right;
403 right_subtree.cmp = t->cmp;
404 right_subtree.keyOff = t->keyOff;
405 if (avl_insert(&right_subtree, n)) {
406 switch (t->root->balance++) {
407 case -1: return False;
408 case 0: return True;
409 }
410 if (t->root->right->balance > 0) {
411 avl_swl(&(t->root));
412 t->root->balance = 0;
413 t->root->left->balance = 0;
414 } else {
415 avl_swr(&(t->root->right));
416 avl_swl(&(t->root));
417 avl_nasty(t->root);
418 }
419 } else {
420 t->root->right=right_subtree.root;
421 }
422 return False;
423 } else {
424 t->root->right = n;
425 if (t->root->balance++) return False;
426 return True;
427 }
428
429 } else {
430 vg_assert2(0, "OSet_Insert: duplicate element added");
431 }
432}
433
434// Insert element e into the AVL tree t. This is just a wrapper for
435// avl_insert() which doesn't return a Bool.
436void VG_(OSet_Insert)(AvlTree* t, void* e)
437{
tom60a4b0b2005-10-12 10:45:27 +0000438 AvlNode* n;
439
njne1b2b962005-08-14 22:13:00 +0000440 vg_assert(t);
441
442 // Initialise. Even though OSet_AllocNode zeroes these fields, we should
443 // do it again in case a node is removed and then re-added to the tree.
tom60a4b0b2005-10-12 10:45:27 +0000444 n = node_of_elem(e);
njne1b2b962005-08-14 22:13:00 +0000445 n->left = 0;
446 n->right = 0;
447 n->balance = 0;
448
449 // Insert into an empty tree
450 if (!t->root) {
451 t->root = n;
452 } else {
453 avl_insert(t, n);
454 }
455
456 t->nElems++;
457 t->stackTop = 0; // So the iterator can't get out of sync
458}
459
460/*--------------------------------------------------------------------*/
461/*--- Lookup ---*/
462/*--------------------------------------------------------------------*/
463
464// Find the *node* in t matching k, or NULL if not found.
465static AvlNode* avl_lookup(AvlTree* t, void* k)
466{
njnafa12262005-12-24 03:10:56 +0000467 Word cmpres;
njn0684dd42005-08-15 02:05:21 +0000468 AvlNode* curr = t->root;
njne1b2b962005-08-14 22:13:00 +0000469
470 if (t->cmp) {
471 // General case
472 while (True) {
473 if (curr == NULL) return NULL;
474 cmpres = slow_cmp(t, k, curr);
475 if (cmpres < 0) curr = curr->left; else
476 if (cmpres > 0) curr = curr->right; else
477 return curr;
478 }
479 } else {
480 // Fast-track special case. We use the no-check version of
481 // elem_of_node because it saves about 10% on lookup time. This
482 // shouldn't be very dangerous because each node will have been
483 // checked on insertion.
njnafa12262005-12-24 03:10:56 +0000484 Word kk = *(Word*)k;
njne1b2b962005-08-14 22:13:00 +0000485 while (True) {
486 if (curr == NULL) return NULL;
njnafa12262005-12-24 03:10:56 +0000487 cmpres = kk - *(Word*)elem_of_node_no_check(curr);
njne1b2b962005-08-14 22:13:00 +0000488 if (cmpres < 0) curr = curr->left; else
489 if (cmpres > 0) curr = curr->right; else
490 return curr;
491 }
492 }
493}
494
495// Find the *element* in t matching k, or NULL if not found.
496void* VG_(OSet_Lookup)(AvlTree* t, void* k)
497{
njn0684dd42005-08-15 02:05:21 +0000498 AvlNode* n;
499 vg_assert(t);
500 n = avl_lookup(t, k);
njne1b2b962005-08-14 22:13:00 +0000501 return ( n ? elem_of_node(n) : NULL );
502}
503
njnaa260e82005-08-17 21:06:07 +0000504// Find the *element* in t matching k, or NULL if not found; use the given
505// comparison function rather than the standard one.
506void* VG_(OSet_LookupWithCmp)(AvlTree* t, void* k, OSetCmp_t cmp)
507{
508 // Save the normal one to the side, then restore once we're done.
509 void* e;
510 OSetCmp_t tmpcmp;
511 vg_assert(t);
512 tmpcmp = t->cmp;
513 t->cmp = cmp;
514 e = VG_(OSet_Lookup)(t, k);
515 t->cmp = tmpcmp;
516 return e;
517}
518
njne1b2b962005-08-14 22:13:00 +0000519// Is there an element matching k?
520Bool VG_(OSet_Contains)(AvlTree* t, void* k)
521{
522 return (NULL != VG_(OSet_Lookup)(t, k));
523}
524
525/*--------------------------------------------------------------------*/
526/*--- Deletion ---*/
527/*--------------------------------------------------------------------*/
528
529static Bool avl_removeroot(AvlTree* t);
530
531// Remove an already-selected node n from the AVL tree t.
532// Returns True if the depth of the tree has shrunk.
533static Bool avl_remove(AvlTree* t, AvlNode* n)
534{
535 Bool ch;
njnafa12262005-12-24 03:10:56 +0000536 Word cmpres = cmp_key_root(t, n);
njne1b2b962005-08-14 22:13:00 +0000537
538 if (cmpres < 0) {
tom60a4b0b2005-10-12 10:45:27 +0000539 AvlTree left_subtree;
njne1b2b962005-08-14 22:13:00 +0000540 // Remove from the left subtree
541 vg_assert(t->root->left);
njne1b2b962005-08-14 22:13:00 +0000542 // Only need to set the used fields in the subtree.
543 left_subtree.root = t->root->left;
544 left_subtree.cmp = t->cmp;
545 left_subtree.keyOff = t->keyOff;
546 ch = avl_remove(&left_subtree, n);
547 t->root->left = left_subtree.root;
548 if (ch) {
549 switch (t->root->balance++) {
550 case -1: return True;
551 case 0: return False;
552 }
553 switch (t->root->right->balance) {
554 case 0:
555 avl_swl(&(t->root));
556 t->root->balance = -1;
557 t->root->left->balance = 1;
558 return False;
559 case 1:
560 avl_swl(&(t->root));
561 t->root->balance = 0;
562 t->root->left->balance = 0;
563 return True;
564 }
565 avl_swr(&(t->root->right));
566 avl_swl(&(t->root));
567 avl_nasty(t->root);
568 return True;
569 } else {
570 return False;
571 }
572
573 } else if (cmpres > 0) {
574 // Remove from the right subtree
575 AvlTree right_subtree;
576 vg_assert(t->root->right);
577 // Only need to set the used fields in the subtree.
578 right_subtree.root = t->root->right;
579 right_subtree.cmp = t->cmp;
580 right_subtree.keyOff = t->keyOff;
581 ch = avl_remove(&right_subtree, n);
582 t->root->right = right_subtree.root;
583 if (ch) {
584 switch (t->root->balance--) {
585 case 1: return True;
586 case 0: return False;
587 }
588 switch (t->root->left->balance) {
589 case 0:
590 avl_swr(&(t->root));
591 t->root->balance = 1;
592 t->root->right->balance = -1;
593 return False;
594 case -1:
595 avl_swr(&(t->root));
596 t->root->balance = 0;
597 t->root->right->balance = 0;
598 return True;
599 }
600 avl_swl(&(t->root->left));
601 avl_swr(&(t->root));
602 avl_nasty(t->root);
603 return True;
604 } else {
605 return False;
606 }
607
608 } else {
609 // Found the node to be removed.
610 vg_assert(t->root == n);
611 return avl_removeroot(t);
612 }
613}
614
615// Remove the root of the AVL tree t.
616// Returns True if the depth of the tree has shrunk.
617static Bool avl_removeroot(AvlTree* t)
618{
njnafa12262005-12-24 03:10:56 +0000619 Bool ch;
njne1b2b962005-08-14 22:13:00 +0000620 AvlNode* n;
621
njne1b2b962005-08-14 22:13:00 +0000622 if (!t->root->left) {
623 if (!t->root->right) {
624 t->root = NULL;
625 return True;
626 }
627 t->root = t->root->right;
628 return True;
629 }
630 if (!t->root->right) {
631 t->root = t->root->left;
632 return True;
633 }
634 if (t->root->balance < 0) {
635 // Remove from the left subtree
636 n = t->root->left;
637 while (n->right) n = n->right;
638 } else {
639 // Remove from the right subtree
640 n = t->root->right;
641 while (n->left) n = n->left;
642 }
643 ch = avl_remove(t, n);
644 n->left = t->root->left;
645 n->right = t->root->right;
646 n->balance = t->root->balance;
647 t->root = n;
648 if (n->balance == 0) return ch;
649 return False;
650}
651
652// Remove and return the element matching the key 'k', or NULL if not present.
653void* VG_(OSet_Remove)(AvlTree* t, void* k)
654{
655 // Have to find the node first, then remove it.
656 AvlNode* n = avl_lookup(t, k);
657 if (n) {
658 avl_remove(t, n);
659 t->nElems--;
660 t->stackTop = 0; // So the iterator can't get out of sync
661 return elem_of_node(n);
662 } else {
663 return NULL;
664 }
665}
666
667/*--------------------------------------------------------------------*/
668/*--- Iterator ---*/
669/*--------------------------------------------------------------------*/
670
671// The iterator is implemented using in-order traversal with an explicit
672// stack, which lets us do the traversal one step at a time and remember
673// where we are between each call to OSet_Next().
674
675void VG_(OSet_ResetIter)(AvlTree* t)
676{
677 vg_assert(t);
678 stackClear(t);
679 if (t->root)
680 stackPush(t, t->root, 1);
681}
682
683void* VG_(OSet_Next)(AvlTree* t)
684{
sewardjdff46d52006-10-17 01:40:33 +0000685 Int i = 0;
686 OSetNode* n = NULL;
njne1b2b962005-08-14 22:13:00 +0000687
688 vg_assert(t);
689
690 // This in-order traversal requires each node to be pushed and popped
691 // three times. These could be avoided by updating nodes in-situ on the
692 // top of the stack, but the push/pop cost is so small that it's worth
693 // keeping this loop in this simpler form.
694 while (stackPop(t, &n, &i)) {
695 switch (i) {
696 case 1:
697 stackPush(t, n, 2);
698 if (n->left) stackPush(t, n->left, 1);
699 break;
700 case 2:
701 stackPush(t, n, 3);
702 return elem_of_node(n);
703 case 3:
704 if (n->right) stackPush(t, n->right, 1);
705 break;
706 }
707 }
708
709 // Stack empty, iterator is exhausted, return NULL
710 return NULL;
711}
712
713/*--------------------------------------------------------------------*/
714/*--- Miscellaneous operations ---*/
715/*--------------------------------------------------------------------*/
716
717Int VG_(OSet_Size)(AvlTree* t)
718{
719 vg_assert(t);
720 return t->nElems;
721}
722
723static void OSet_Print2( AvlTree* t, AvlNode* n,
724 Char*(*strElem)(void *), Int p )
725{
726 // This is a recursive in-order traversal.
727 Int q = p;
728 if (NULL == n) return;
729 if (n->right) OSet_Print2(t, n->right, strElem, p+1);
730 while (q--) VG_(printf)(".. ");
731 VG_(printf)("%s\n", strElem(elem_of_node(n)));
732 if (n->left) OSet_Print2(t, n->left, strElem, p+1);
733}
734
735__attribute__((unused))
736static void OSet_Print( AvlTree* t, const HChar *where, Char*(*strElem)(void *) )
737{
738 VG_(printf)("-- start %s ----------------\n", where);
739 OSet_Print2(t, t->root, strElem, 0);
740 VG_(printf)("-- end %s ----------------\n", where);
741}
742
743/*--------------------------------------------------------------------*/
744/*--- end ---*/
745/*--------------------------------------------------------------------*/