1 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 10 Copyright (C) 2005-2012 Nicholas Nethercote 11 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 45// corrupted the metadata. So the overhead is 12 bytes on 32-bit 46// platforms and 24 bytes on 64-bit platforms. 47// - 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 OSetGen_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 OSetGen_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#include "pub_tool_poolalloc.h" 84 85/*--------------------------------------------------------------------*/ 86/*--- Types and constants ---*/ 87/*--------------------------------------------------------------------*/ 88 89typedef struct _OSetNode OSetNode; 90 91// Internal names for the OSet types. 92typedef OSet AvlTree; 93typedef OSetNode AvlNode; 94 95// The padding ensures that magic is right at the end of the node, 96// regardless of the machine's word size, so that any overwrites will be 97// detected earlier. 98struct _OSetNode { 99 AvlNode* left; 100 AvlNode* right; 101 Char balance; 102 Char padding[sizeof(void*)-sizeof(Char)-sizeof(Short)]; 103 Short magic; 104}; 105 106#define STACK_MAX 32 // At most 2**32 entries can be iterated over 107#define OSET_MAGIC 0x5b1f 108 109// An OSet (AVL tree). If cmp is NULL, the key must be a UWord, and must 110// be the first word in the element. If cmp is set, arbitrary keys in 111// arbitrary positions can be used. 112struct _OSet { 113 SizeT keyOff; // key offset 114 OSetCmp_t cmp; // compare a key and an element, or NULL 115 OSetAlloc_t alloc; // allocator 116 HChar* cc; // cc for allocator 117 OSetFree_t free; // deallocator 118 PoolAlloc* node_pa; // (optional) pool allocator for nodes. 119 SizeT maxEltSize; // for node_pa, must be > 0. Otherwise unused. 120 Word nElems; // number of elements in the tree 121 AvlNode* root; // root node 122 123 AvlNode* nodeStack[STACK_MAX]; // Iterator node stack 124 Int numStack[STACK_MAX]; // Iterator num stack 125 Int stackTop; // Iterator stack pointer, one past end 126}; 127 128/*--------------------------------------------------------------------*/ 129/*--- Helper operations ---*/ 130/*--------------------------------------------------------------------*/ 131 132// Given a pointer to the node's element, return the pointer to the AvlNode 133// structure. If the node has a bad magic number, it will die with an 134// assertion failure. 135static inline 136AvlNode* node_of_elem(const void *elem) 137{ 138 AvlNode* n = (AvlNode*)((Addr)elem - sizeof(AvlNode)); 139 vg_assert2(n->magic == OSET_MAGIC, 140 "bad magic on node %p = %x (expected %x)\n" 141 "possible causes:\n" 142 " - node not allocated with VG_(OSetGen_AllocNode)()?\n" 143 " - node metadata corrupted by underwriting start of element?\n", 144 n, n->magic, OSET_MAGIC); 145 return n; 146} 147 148// Given an AvlNode, return the pointer to the element. 149static inline 150void* elem_of_node(const AvlNode *n) 151{ 152 vg_assert2(n->magic == OSET_MAGIC, 153 "bad magic on node %p = %x (expected %x)\n" 154 "possible causes:\n" 155 " - node metadata corrupted by overwriting end of element?\n", 156 n, n->magic, OSET_MAGIC); 157 return (void*)((Addr)n + sizeof(AvlNode)); 158} 159 160// Like elem_of_node, but no magic checking. 161static inline 162void* elem_of_node_no_check(const AvlNode *n) 163{ 164 return (void*)((Addr)n + sizeof(AvlNode)); 165} 166 167static inline 168void* slow_key_of_node(AvlTree* t, AvlNode* n) 169{ 170 return (void*)((Addr)elem_of_node(n) + t->keyOff); 171} 172 173static inline 174void* fast_key_of_node(AvlNode* n) 175{ 176 return elem_of_node(n); 177} 178 179// Compare the first word of each element. Inlining is *crucial*. 180static inline Word fast_cmp(const void* k, const AvlNode* n) 181{ 182 UWord w1 = *(UWord*)k; 183 UWord w2 = *(UWord*)elem_of_node(n); 184 // In previous versions, we tried to do this faster by doing 185 // "return w1 - w2". But it didn't work reliably, because the 186 // complete result of subtracting two N-bit numbers is an N+1-bit 187 // number, and what the caller is interested in is the sign of 188 // the complete N+1-bit result. The branching version is slightly 189 // slower, but safer and easier to understand. 190 if (w1 > w2) return 1; 191 if (w1 < w2) return -1; 192 return 0; 193} 194 195// Compare a key and an element. Inlining is *crucial*. 196static 197inline Word slow_cmp(const AvlTree* t, const void* k, const AvlNode* n) 198{ 199 return t->cmp(k, elem_of_node(n)); 200} 201 202 203// Swing to the left. Warning: no balance maintainance. 204static void avl_swl ( AvlNode** root ) 205{ 206 AvlNode* a = *root; 207 AvlNode* b = a->right; 208 *root = b; 209 a->right = b->left; 210 b->left = a; 211} 212 213// Swing to the right. Warning: no balance maintainance. 214static void avl_swr ( AvlNode** root ) 215{ 216 AvlNode* a = *root; 217 AvlNode* b = a->left; 218 *root = b; 219 a->left = b->right; 220 b->right = a; 221} 222 223// Balance maintainance after especially nasty swings. 224static void avl_nasty ( AvlNode* root ) 225{ 226 switch (root->balance) { 227 case -1: 228 root->left->balance = 0; 229 root->right->balance = 1; 230 break; 231 case 1: 232 root->left->balance =-1; 233 root->right->balance = 0; 234 break; 235 case 0: 236 root->left->balance = 0; 237 root->right->balance = 0; 238 } 239 root->balance = 0; 240} 241 242 243// Clear the iterator stack. 244static void stackClear(AvlTree* t) 245{ 246 Int i; 247 vg_assert(t); 248 for (i = 0; i < STACK_MAX; i++) { 249 t->nodeStack[i] = NULL; 250 t->numStack[i] = 0; 251 } 252 t->stackTop = 0; 253} 254 255// Push onto the iterator stack. 256static inline void stackPush(AvlTree* t, AvlNode* n, Int i) 257{ 258 vg_assert(t->stackTop < STACK_MAX); 259 vg_assert(1 <= i && i <= 3); 260 t->nodeStack[t->stackTop] = n; 261 t-> numStack[t->stackTop] = i; 262 t->stackTop++; 263} 264 265// Pop from the iterator stack. 266static inline Bool stackPop(AvlTree* t, AvlNode** n, Int* i) 267{ 268 vg_assert(t->stackTop <= STACK_MAX); 269 270 if (t->stackTop > 0) { 271 t->stackTop--; 272 *n = t->nodeStack[t->stackTop]; 273 *i = t-> numStack[t->stackTop]; 274 vg_assert(1 <= *i && *i <= 3); 275 t->nodeStack[t->stackTop] = NULL; 276 t-> numStack[t->stackTop] = 0; 277 return True; 278 } else { 279 return False; 280 } 281} 282 283/*--------------------------------------------------------------------*/ 284/*--- Creating and destroying AvlTrees and AvlNodes ---*/ 285/*--------------------------------------------------------------------*/ 286 287// The underscores avoid GCC complaints about overshadowing global names. 288AvlTree* VG_(OSetGen_Create)(PtrdiffT _keyOff, OSetCmp_t _cmp, 289 OSetAlloc_t _alloc, HChar* _cc, 290 OSetFree_t _free) 291{ 292 AvlTree* t; 293 294 // Check the padding is right and the AvlNode is the expected size. 295 vg_assert(sizeof(AvlNode) == 3*sizeof(void*)); 296 297 // Sanity check args 298 vg_assert(_alloc); 299 vg_assert(_free); 300 if (!_cmp) vg_assert(0 == _keyOff); // If no cmp, offset must be zero 301 302 t = _alloc(_cc, sizeof(AvlTree)); 303 t->keyOff = _keyOff; 304 t->cmp = _cmp; 305 t->alloc = _alloc; 306 t->cc = _cc; 307 t->free = _free; 308 t->node_pa = NULL; 309 t->maxEltSize = 0; // Just in case it would be wrongly used. 310 t->nElems = 0; 311 t->root = NULL; 312 stackClear(t); 313 314 return t; 315} 316 317AvlTree* VG_(OSetGen_Create_With_Pool)(PtrdiffT _keyOff, OSetCmp_t _cmp, 318 OSetAlloc_t _alloc, HChar* _cc, 319 OSetFree_t _free, 320 SizeT _poolSize, 321 SizeT _maxEltSize) 322{ 323 AvlTree* t; 324 325 t = VG_(OSetGen_Create) (_keyOff, _cmp, 326 _alloc, _cc, 327 _free); 328 329 vg_assert (_poolSize > 0); 330 vg_assert (_maxEltSize > 0); 331 t->maxEltSize = _maxEltSize; 332 t->node_pa = VG_(newPA)(sizeof(AvlNode) 333 + VG_ROUNDUP(_maxEltSize, sizeof(void*)), 334 _poolSize, 335 t->alloc, 336 _cc, 337 t->free); 338 VG_(addRefPA) (t->node_pa); 339 340 return t; 341} 342 343AvlTree* VG_(OSetGen_EmptyClone) (AvlTree* os) 344{ 345 AvlTree* t; 346 347 vg_assert(os); 348 349 t = os->alloc(os->cc, sizeof(AvlTree)); 350 t->keyOff = os->keyOff; 351 t->cmp = os->cmp; 352 t->alloc = os->alloc; 353 t->cc = os->cc; 354 t->free = os->free; 355 t->node_pa = os->node_pa; 356 if (t->node_pa) 357 VG_(addRefPA) (t->node_pa); 358 t->maxEltSize = os->maxEltSize; 359 t->nElems = 0; 360 t->root = NULL; 361 stackClear(t); 362 363 return t; 364} 365 366AvlTree* VG_(OSetWord_Create)(OSetAlloc_t _alloc, HChar* _cc, 367 OSetFree_t _free) 368{ 369 return VG_(OSetGen_Create)(/*keyOff*/0, /*cmp*/NULL, _alloc, _cc, _free); 370} 371 372// Destructor, frees up all memory held by remaining nodes. 373void VG_(OSetGen_Destroy)(AvlTree* t) 374{ 375 Bool has_node_pa; 376 vg_assert(t); 377 378 has_node_pa = t->node_pa != NULL; 379 380 /* 381 * If we are the only remaining user of this pool allocator, release all 382 * the elements by deleting the pool allocator. That's more efficient than 383 * deleting tree nodes one by one. 384 */ 385 if (!has_node_pa || VG_(releasePA)(t->node_pa) > 0) { 386 AvlNode* n = NULL; 387 Int i = 0; 388 Word sz = 0; 389 390 stackClear(t); 391 if (t->root) 392 stackPush(t, t->root, 1); 393 394 /* Free all the AvlNodes. This is a post-order traversal, because we */ 395 /* must free all children of a node before the node itself. */ 396 while (stackPop(t, &n, &i)) { 397 switch (i) { 398 case 1: 399 stackPush(t, n, 2); 400 if (n->left) stackPush(t, n->left, 1); 401 break; 402 case 2: 403 stackPush(t, n, 3); 404 if (n->right) stackPush(t, n->right, 1); 405 break; 406 case 3: 407 if (has_node_pa) 408 VG_(freeEltPA) (t->node_pa, n); 409 else 410 t->free(n); 411 sz++; 412 break; 413 } 414 } 415 vg_assert(sz == t->nElems); 416 } 417 418 /* Free the AvlTree itself. */ 419 t->free(t); 420} 421 422void VG_(OSetWord_Destroy)(AvlTree* t) 423{ 424 VG_(OSetGen_Destroy)(t); 425} 426 427// Allocate and initialise a new node. 428void* VG_(OSetGen_AllocNode)(AvlTree* t, SizeT elemSize) 429{ 430 AvlNode* n; 431 Int nodeSize = sizeof(AvlNode) + elemSize; 432 vg_assert(elemSize > 0); 433 if (t->node_pa) { 434 vg_assert(elemSize <= t->maxEltSize); 435 n = VG_(allocEltPA) (t->node_pa); 436 } else { 437 n = t->alloc( t->cc, nodeSize ); 438 } 439 VG_(memset)(n, 0, nodeSize); 440 n->magic = OSET_MAGIC; 441 return elem_of_node(n); 442} 443 444void VG_(OSetGen_FreeNode)(AvlTree* t, void* e) 445{ 446 if (t->node_pa) 447 VG_(freeEltPA) (t->node_pa, node_of_elem (e)); 448 else 449 t->free( node_of_elem(e) ); 450} 451 452/*--------------------------------------------------------------------*/ 453/*--- Insertion ---*/ 454/*--------------------------------------------------------------------*/ 455 456static inline Word cmp_key_root(AvlTree* t, AvlNode* n) 457{ 458 return t->cmp 459 ? slow_cmp(t, slow_key_of_node(t, n), t->root) 460 : fast_cmp( fast_key_of_node( n), t->root); 461} 462 463// Insert element e into the non-empty AVL tree t. 464// Returns True if the depth of the tree has grown. 465static Bool avl_insert(AvlTree* t, AvlNode* n) 466{ 467 Word cmpres = cmp_key_root(t, n); 468 469 if (cmpres < 0) { 470 // Insert into the left subtree. 471 if (t->root->left) { 472 // Only need to set the used fields in the subtree. 473 AvlTree left_subtree; 474 left_subtree.root = t->root->left; 475 left_subtree.cmp = t->cmp; 476 left_subtree.keyOff = t->keyOff; 477 if (avl_insert(&left_subtree, n)) { 478 switch (t->root->balance--) { 479 case 1: return False; 480 case 0: return True; 481 } 482 if (t->root->left->balance < 0) { 483 avl_swr(&(t->root)); 484 t->root->balance = 0; 485 t->root->right->balance = 0; 486 } else { 487 avl_swl(&(t->root->left)); 488 avl_swr(&(t->root)); 489 avl_nasty(t->root); 490 } 491 } else { 492 t->root->left=left_subtree.root; 493 } 494 return False; 495 } else { 496 t->root->left = n; 497 if (t->root->balance--) return False; 498 return True; 499 } 500 501 } else if (cmpres > 0) { 502 // Insert into the right subtree 503 if (t->root->right) { 504 // Only need to set the used fields in the subtree. 505 AvlTree right_subtree; 506 right_subtree.root = t->root->right; 507 right_subtree.cmp = t->cmp; 508 right_subtree.keyOff = t->keyOff; 509 if (avl_insert(&right_subtree, n)) { 510 switch (t->root->balance++) { 511 case -1: return False; 512 case 0: return True; 513 } 514 if (t->root->right->balance > 0) { 515 avl_swl(&(t->root)); 516 t->root->balance = 0; 517 t->root->left->balance = 0; 518 } else { 519 avl_swr(&(t->root->right)); 520 avl_swl(&(t->root)); 521 avl_nasty(t->root); 522 } 523 } else { 524 t->root->right=right_subtree.root; 525 } 526 return False; 527 } else { 528 t->root->right = n; 529 if (t->root->balance++) return False; 530 return True; 531 } 532 533 } else { 534 vg_assert2(0, "OSet{Word,Gen}_Insert: duplicate element added"); 535 } 536} 537 538// Insert element e into the AVL tree t. This is just a wrapper for 539// avl_insert() which doesn't return a Bool. 540void VG_(OSetGen_Insert)(AvlTree* t, void* e) 541{ 542 AvlNode* n; 543 544 vg_assert(t); 545 546 // Initialise. Even though OSetGen_AllocNode zeroes these fields, 547 // we should do it again in case a node is removed and then 548 // re-added to the tree. 549 n = node_of_elem(e); 550 n->left = 0; 551 n->right = 0; 552 n->balance = 0; 553 554 // Insert into an empty tree 555 if (!t->root) { 556 t->root = n; 557 } else { 558 avl_insert(t, n); 559 } 560 561 t->nElems++; 562 t->stackTop = 0; // So the iterator can't get out of sync 563} 564 565void VG_(OSetWord_Insert)(AvlTree* t, UWord val) 566{ 567 Word* node = VG_(OSetGen_AllocNode)(t, sizeof(UWord)); 568 *node = val; 569 VG_(OSetGen_Insert)(t, node); 570} 571 572/*--------------------------------------------------------------------*/ 573/*--- Lookup ---*/ 574/*--------------------------------------------------------------------*/ 575 576// Find the *node* in t matching k, or NULL if not found. 577static AvlNode* avl_lookup(const AvlTree* t, const void* k) 578{ 579 Word cmpres; 580 AvlNode* curr = t->root; 581 582 if (t->cmp) { 583 // General case 584 while (True) { 585 if (curr == NULL) return NULL; 586 cmpres = slow_cmp(t, k, curr); 587 if (cmpres < 0) curr = curr->left; 588 else if (cmpres > 0) curr = curr->right; 589 else return curr; 590 } 591 } else { 592 // Fast-track special case. We use the no-check version of 593 // elem_of_node because it saves about 10% on lookup time. This 594 // shouldn't be very dangerous because each node will have been 595 // checked on insertion. 596 UWord w1 = *(UWord*)k; 597 UWord w2; 598 while (True) { 599 if (curr == NULL) return NULL; 600 w2 = *(UWord*)elem_of_node_no_check(curr); 601 if (w1 < w2) curr = curr->left; 602 else if (w1 > w2) curr = curr->right; 603 else return curr; 604 } 605 } 606} 607 608// Find the *element* in t matching k, or NULL if not found. 609void* VG_(OSetGen_Lookup)(const AvlTree* t, const void* k) 610{ 611 AvlNode* n; 612 vg_assert(t); 613 n = avl_lookup(t, k); 614 return ( n ? elem_of_node(n) : NULL ); 615} 616 617// Find the *element* in t matching k, or NULL if not found; use the given 618// comparison function rather than the standard one. 619void* VG_(OSetGen_LookupWithCmp)(AvlTree* t, const void* k, OSetCmp_t cmp) 620{ 621 // Save the normal one to the side, then restore once we're done. 622 void* e; 623 OSetCmp_t tmpcmp; 624 vg_assert(t); 625 tmpcmp = t->cmp; 626 t->cmp = cmp; 627 e = VG_(OSetGen_Lookup)(t, k); 628 t->cmp = tmpcmp; 629 return e; 630} 631 632// Is there an element matching k? 633Bool VG_(OSetGen_Contains)(const AvlTree* t, const void* k) 634{ 635 return (NULL != VG_(OSetGen_Lookup)(t, k)); 636} 637 638Bool VG_(OSetWord_Contains)(AvlTree* t, UWord val) 639{ 640 return (NULL != VG_(OSetGen_Lookup)(t, &val)); 641} 642 643/*--------------------------------------------------------------------*/ 644/*--- Deletion ---*/ 645/*--------------------------------------------------------------------*/ 646 647static Bool avl_removeroot(AvlTree* t); 648 649// Remove an already-selected node n from the AVL tree t. 650// Returns True if the depth of the tree has shrunk. 651static Bool avl_remove(AvlTree* t, AvlNode* n) 652{ 653 Bool ch; 654 Word cmpres = cmp_key_root(t, n); 655 656 if (cmpres < 0) { 657 AvlTree left_subtree; 658 // Remove from the left subtree 659 vg_assert(t->root->left); 660 // Only need to set the used fields in the subtree. 661 left_subtree.root = t->root->left; 662 left_subtree.cmp = t->cmp; 663 left_subtree.keyOff = t->keyOff; 664 ch = avl_remove(&left_subtree, n); 665 t->root->left = left_subtree.root; 666 if (ch) { 667 switch (t->root->balance++) { 668 case -1: return True; 669 case 0: return False; 670 } 671 switch (t->root->right->balance) { 672 case 0: 673 avl_swl(&(t->root)); 674 t->root->balance = -1; 675 t->root->left->balance = 1; 676 return False; 677 case 1: 678 avl_swl(&(t->root)); 679 t->root->balance = 0; 680 t->root->left->balance = 0; 681 return True; 682 } 683 avl_swr(&(t->root->right)); 684 avl_swl(&(t->root)); 685 avl_nasty(t->root); 686 return True; 687 } else { 688 return False; 689 } 690 691 } else if (cmpres > 0) { 692 // Remove from the right subtree 693 AvlTree right_subtree; 694 vg_assert(t->root->right); 695 // Only need to set the used fields in the subtree. 696 right_subtree.root = t->root->right; 697 right_subtree.cmp = t->cmp; 698 right_subtree.keyOff = t->keyOff; 699 ch = avl_remove(&right_subtree, n); 700 t->root->right = right_subtree.root; 701 if (ch) { 702 switch (t->root->balance--) { 703 case 1: return True; 704 case 0: return False; 705 } 706 switch (t->root->left->balance) { 707 case 0: 708 avl_swr(&(t->root)); 709 t->root->balance = 1; 710 t->root->right->balance = -1; 711 return False; 712 case -1: 713 avl_swr(&(t->root)); 714 t->root->balance = 0; 715 t->root->right->balance = 0; 716 return True; 717 } 718 avl_swl(&(t->root->left)); 719 avl_swr(&(t->root)); 720 avl_nasty(t->root); 721 return True; 722 } else { 723 return False; 724 } 725 726 } else { 727 // Found the node to be removed. 728 vg_assert(t->root == n); 729 return avl_removeroot(t); 730 } 731} 732 733// Remove the root of the AVL tree t. 734// Returns True if the depth of the tree has shrunk. 735static Bool avl_removeroot(AvlTree* t) 736{ 737 Bool ch; 738 AvlNode* n; 739 740 if (!t->root->left) { 741 if (!t->root->right) { 742 t->root = NULL; 743 return True; 744 } 745 t->root = t->root->right; 746 return True; 747 } 748 if (!t->root->right) { 749 t->root = t->root->left; 750 return True; 751 } 752 if (t->root->balance < 0) { 753 // Remove from the left subtree 754 n = t->root->left; 755 while (n->right) n = n->right; 756 } else { 757 // Remove from the right subtree 758 n = t->root->right; 759 while (n->left) n = n->left; 760 } 761 ch = avl_remove(t, n); 762 n->left = t->root->left; 763 n->right = t->root->right; 764 n->balance = t->root->balance; 765 t->root = n; 766 if (n->balance == 0) return ch; 767 return False; 768} 769 770// Remove and return the element matching the key 'k', or NULL 771// if not present. 772void* VG_(OSetGen_Remove)(AvlTree* t, const void* k) 773{ 774 // Have to find the node first, then remove it. 775 AvlNode* n = avl_lookup(t, k); 776 if (n) { 777 avl_remove(t, n); 778 t->nElems--; 779 t->stackTop = 0; // So the iterator can't get out of sync 780 return elem_of_node(n); 781 } else { 782 return NULL; 783 } 784} 785 786Bool VG_(OSetWord_Remove)(AvlTree* t, UWord val) 787{ 788 void* n = VG_(OSetGen_Remove)(t, &val); 789 if (n) { 790 VG_(OSetGen_FreeNode)(t, n); 791 return True; 792 } else { 793 return False; 794 } 795} 796 797/*--------------------------------------------------------------------*/ 798/*--- Iterator ---*/ 799/*--------------------------------------------------------------------*/ 800 801// The iterator is implemented using in-order traversal with an explicit 802// stack, which lets us do the traversal one step at a time and remember 803// where we are between each call to OSetGen_Next(). 804 805void VG_(OSetGen_ResetIter)(AvlTree* t) 806{ 807 vg_assert(t); 808 stackClear(t); 809 if (t->root) 810 stackPush(t, t->root, 1); 811} 812 813void VG_(OSetWord_ResetIter)(AvlTree* t) 814{ 815 VG_(OSetGen_ResetIter)(t); 816} 817 818void* VG_(OSetGen_Next)(AvlTree* t) 819{ 820 Int i = 0; 821 OSetNode* n = NULL; 822 823 vg_assert(t); 824 825 // This in-order traversal requires each node to be pushed and popped 826 // three times. These could be avoided by updating nodes in-situ on the 827 // top of the stack, but the push/pop cost is so small that it's worth 828 // keeping this loop in this simpler form. 829 while (stackPop(t, &n, &i)) { 830 switch (i) { 831 case 1: case_1: 832 stackPush(t, n, 2); 833 /* if (n->left) stackPush(t, n->left, 1); */ 834 if (n->left) { n = n->left; goto case_1; } 835 break; 836 case 2: 837 stackPush(t, n, 3); 838 return elem_of_node(n); 839 case 3: 840 /* if (n->right) stackPush(t, n->right, 1); */ 841 if (n->right) { n = n->right; goto case_1; } 842 break; 843 } 844 } 845 846 // Stack empty, iterator is exhausted, return NULL 847 return NULL; 848} 849 850Bool VG_(OSetWord_Next)(AvlTree* t, UWord* val) 851{ 852 UWord* n = VG_(OSetGen_Next)(t); 853 if (n) { 854 *val = *n; 855 return True; 856 } else { 857 return False; 858 } 859} 860 861// set up 'oset' for iteration so that the first key subsequently 862// produced VG_(OSetGen_Next) is the smallest key in the map 863// >= start_at. Naturally ">=" is defined by the comparison 864// function supplied to VG_(OSetGen_Create). 865void VG_(OSetGen_ResetIterAt)(AvlTree* oset, const void* k) 866{ 867 Int i; 868 AvlNode *n, *t; 869 Word cmpresS; /* signed */ 870 UWord cmpresU; /* unsigned */ 871 872 vg_assert(oset); 873 stackClear(oset); 874 875 if (!oset->root) 876 return; 877 878 n = NULL; 879 // We need to do regular search and fill in the stack. 880 t = oset->root; 881 882 while (True) { 883 if (t == NULL) return; 884 885 if (oset->cmp) { 886 cmpresS = (Word)slow_cmp(oset, k, t); 887 } else { 888 cmpresS = fast_cmp(k, t); 889 } 890 891 /* Switch the sense of the comparison, since the comparison 892 order of args (k vs t) above is opposite to that of the 893 corresponding code in hg_wordfm.c. */ 894 if (cmpresS < 0) { cmpresS = 1; } 895 else if (cmpresS > 0) { cmpresS = -1; } 896 897 if (cmpresS == 0) { 898 // We found the exact key -- we are done. 899 // The iteration should start with this node. 900 stackPush(oset, t, 2); 901 // The stack now looks like {2, 2, ... ,2, 2} 902 return; 903 } 904 cmpresU = (UWord)cmpresS; 905 cmpresU >>=/*unsigned*/ (8 * sizeof(cmpresU) - 1); 906 vg_assert(cmpresU == 0 || cmpresU == 1); 907 if (!cmpresU) { 908 // Push this node only if we go to the left child. 909 stackPush(oset, t, 2); 910 } 911 t = cmpresU==0 ? t->left : t->right; 912 } 913 if (stackPop(oset, &n, &i)) { 914 // If we've pushed something to stack and did not find the exact key, 915 // we must fix the top element of stack. 916 vg_assert(i == 2); 917 stackPush(oset, n, 3); 918 // the stack looks like {2, 2, ..., 2, 3} 919 } 920} 921 922/*--------------------------------------------------------------------*/ 923/*--- Miscellaneous operations ---*/ 924/*--------------------------------------------------------------------*/ 925 926Word VG_(OSetGen_Size)(const AvlTree* t) 927{ 928 vg_assert(t); 929 return t->nElems; 930} 931 932Word VG_(OSetWord_Size)(AvlTree* t) 933{ 934 return VG_(OSetGen_Size)(t); 935} 936 937static void OSet_Print2( AvlTree* t, AvlNode* n, 938 Char*(*strElem)(void *), Int p ) 939{ 940 // This is a recursive in-order traversal. 941 Int q = p; 942 if (NULL == n) return; 943 if (n->right) OSet_Print2(t, n->right, strElem, p+1); 944 while (q--) VG_(printf)(".. "); 945 VG_(printf)("%s\n", strElem(elem_of_node(n))); 946 if (n->left) OSet_Print2(t, n->left, strElem, p+1); 947} 948 949__attribute__((unused)) 950static void OSet_Print( AvlTree* t, const HChar *where, Char*(*strElem)(void *) ) 951{ 952 VG_(printf)("-- start %s ----------------\n", where); 953 OSet_Print2(t, t->root, strElem, 0); 954 VG_(printf)("-- end %s ----------------\n", where); 955} 956 957/*--------------------------------------------------------------------*/ 958/*--- end ---*/ 959/*--------------------------------------------------------------------*/ 960