blob: b839a38ede8666d54182d439ec5e8272b96b2022 [file] [log] [blame]
sewardjb4112022007-11-09 22:49:28 +00001
2/*--------------------------------------------------------------------*/
3/*--- An AVL tree based finite map for word keys and word values. ---*/
4/*--- Inspired by Haskell's "FiniteMap" library. ---*/
5/*--- hg_wordfm.c ---*/
6/*--------------------------------------------------------------------*/
7
8/*
9 This file is part of Helgrind, a Valgrind tool for detecting errors
10 in threaded programs.
11
12 Copyright (C) 2007-2007 Julian Seward
13 jseward@acm.org
14
15 This code is based on previous work by Nicholas Nethercote
16 (coregrind/m_oset.c) which is
17
18 Copyright (C) 2005-2007 Nicholas Nethercote
19 njn@valgrind.org
20
21 which in turn was derived partially from:
22
23 AVL C library
24 Copyright (C) 2000,2002 Daniel Nagy
25
26 This program is free software; you can redistribute it and/or
27 modify it under the terms of the GNU General Public License as
28 published by the Free Software Foundation; either version 2 of
29 the License, or (at your option) any later version.
30 [...]
31
32 (taken from libavl-0.4/debian/copyright)
33
34 This program is free software; you can redistribute it and/or
35 modify it under the terms of the GNU General Public License as
36 published by the Free Software Foundation; either version 2 of the
37 License, or (at your option) any later version.
38
39 This program is distributed in the hope that it will be useful, but
40 WITHOUT ANY WARRANTY; without even the implied warranty of
41 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42 General Public License for more details.
43
44 You should have received a copy of the GNU General Public License
45 along with this program; if not, write to the Free Software
46 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
47 02111-1307, USA.
48
49 The GNU General Public License is contained in the file COPYING.
50*/
51
52#include "pub_tool_basics.h"
53#include "pub_tool_libcassert.h"
54#include "pub_tool_libcbase.h"
55
56#define HG_(str) VGAPPEND(vgHelgrind_,str)
57#include "hg_wordfm.h"
58
59//------------------------------------------------------------------//
60//--- WordFM ---//
61//--- Implementation ---//
62//------------------------------------------------------------------//
63
64/* One element of the AVL tree */
65typedef
66 struct _AvlNode {
67 Word key;
68 Word val;
69 struct _AvlNode* child[2]; /* [0] is left subtree, [1] is right */
70 Char balance; /* do not make this unsigned */
71 }
72 AvlNode;
73
74typedef
75 struct {
76 Word w;
77 Bool b;
78 }
79 MaybeWord;
80
81#define WFM_STKMAX 32 // At most 2**32 entries can be iterated over
82
83struct _WordFM {
84 AvlNode* root;
85 void* (*alloc_nofail)( SizeT );
86 void (*dealloc)(void*);
87 Word (*kCmp)(Word,Word);
88 AvlNode* nodeStack[WFM_STKMAX]; // Iterator node stack
89 Int numStack[WFM_STKMAX]; // Iterator num stack
90 Int stackTop; // Iterator stack pointer, one past end
91};
92
93/* forward */
94static Bool avl_removeroot_wrk(AvlNode** t, Word(*kCmp)(Word,Word));
95
96/* Swing to the left. Warning: no balance maintainance. */
97static void avl_swl ( AvlNode** root )
98{
99 AvlNode* a = *root;
100 AvlNode* b = a->child[1];
101 *root = b;
102 a->child[1] = b->child[0];
103 b->child[0] = a;
104}
105
106/* Swing to the right. Warning: no balance maintainance. */
107static void avl_swr ( AvlNode** root )
108{
109 AvlNode* a = *root;
110 AvlNode* b = a->child[0];
111 *root = b;
112 a->child[0] = b->child[1];
113 b->child[1] = a;
114}
115
116/* Balance maintainance after especially nasty swings. */
117static void avl_nasty ( AvlNode* root )
118{
119 switch (root->balance) {
120 case -1:
121 root->child[0]->balance = 0;
122 root->child[1]->balance = 1;
123 break;
124 case 1:
125 root->child[0]->balance = -1;
126 root->child[1]->balance = 0;
127 break;
128 case 0:
129 root->child[0]->balance = 0;
130 root->child[1]->balance = 0;
131 break;
132 default:
133 tl_assert(0);
134 }
135 root->balance=0;
136}
137
138/* Find size of a non-NULL tree. */
139static Word size_avl_nonNull ( AvlNode* nd )
140{
141 return 1 + (nd->child[0] ? size_avl_nonNull(nd->child[0]) : 0)
142 + (nd->child[1] ? size_avl_nonNull(nd->child[1]) : 0);
143}
144
145/* Insert element a into the AVL tree t. Returns True if the depth of
146 the tree has grown. If element with that key is already present,
147 just copy a->val to existing node, first returning old ->val field
148 of existing node in *oldV, so that the caller can finalize it
149 however it wants.
150*/
151static
152Bool avl_insert_wrk ( AvlNode** rootp,
153 /*OUT*/MaybeWord* oldV,
154 AvlNode* a,
155 Word (*kCmp)(Word,Word) )
156{
157 Word cmpres;
158
159 /* initialize */
160 a->child[0] = 0;
161 a->child[1] = 0;
162 a->balance = 0;
163 oldV->b = False;
164
165 /* insert into an empty tree? */
166 if (!(*rootp)) {
167 (*rootp) = a;
168 return True;
169 }
170
171 cmpres = kCmp ? /*boxed*/ kCmp( (*rootp)->key, a->key )
172 : /*unboxed*/ ((Word)(*rootp)->key) - ((Word)a->key);
173
174 if (cmpres > 0) {
175 /* insert into the left subtree */
176 if ((*rootp)->child[0]) {
177 AvlNode* left_subtree = (*rootp)->child[0];
178 if (avl_insert_wrk(&left_subtree, oldV, a, kCmp)) {
179 switch ((*rootp)->balance--) {
180 case 1: return False;
181 case 0: return True;
182 case -1: break;
183 default: tl_assert(0);
184 }
185 if ((*rootp)->child[0]->balance < 0) {
186 avl_swr( rootp );
187 (*rootp)->balance = 0;
188 (*rootp)->child[1]->balance = 0;
189 } else {
190 avl_swl( &((*rootp)->child[0]) );
191 avl_swr( rootp );
192 avl_nasty( *rootp );
193 }
194 } else {
195 (*rootp)->child[0] = left_subtree;
196 }
197 return False;
198 } else {
199 (*rootp)->child[0] = a;
200 if ((*rootp)->balance--)
201 return False;
202 return True;
203 }
204 tl_assert(0);/*NOTREACHED*/
205 }
206 else
207 if (cmpres < 0) {
208 /* insert into the right subtree */
209 if ((*rootp)->child[1]) {
210 AvlNode* right_subtree = (*rootp)->child[1];
211 if (avl_insert_wrk(&right_subtree, oldV, a, kCmp)) {
212 switch((*rootp)->balance++){
213 case -1: return False;
214 case 0: return True;
215 case 1: break;
216 default: tl_assert(0);
217 }
218 if ((*rootp)->child[1]->balance > 0) {
219 avl_swl( rootp );
220 (*rootp)->balance = 0;
221 (*rootp)->child[0]->balance = 0;
222 } else {
223 avl_swr( &((*rootp)->child[1]) );
224 avl_swl( rootp );
225 avl_nasty( *rootp );
226 }
227 } else {
228 (*rootp)->child[1] = right_subtree;
229 }
230 return False;
231 } else {
232 (*rootp)->child[1] = a;
233 if ((*rootp)->balance++)
234 return False;
235 return True;
236 }
237 tl_assert(0);/*NOTREACHED*/
238 }
239 else {
240 /* cmpres == 0, a duplicate - replace the val, but don't
241 incorporate the node in the tree */
242 oldV->b = True;
243 oldV->w = (*rootp)->val;
244 (*rootp)->val = a->val;
245 return False;
246 }
247}
248
249/* Remove an element a from the AVL tree t. a must be part of
250 the tree. Returns True if the depth of the tree has shrunk.
251*/
252static
253Bool avl_remove_wrk ( AvlNode** rootp,
254 AvlNode* a,
255 Word(*kCmp)(Word,Word) )
256{
257 Bool ch;
258 Word cmpres;
259 cmpres = kCmp ? /*boxed*/ kCmp( (*rootp)->key, a->key )
260 : /*unboxed*/ ((Word)(*rootp)->key) - ((Word)a->key);
261
262 if (cmpres > 0){
263 /* remove from the left subtree */
264 AvlNode* left_subtree = (*rootp)->child[0];
265 tl_assert(left_subtree);
266 ch = avl_remove_wrk(&left_subtree, a, kCmp);
267 (*rootp)->child[0]=left_subtree;
268 if (ch) {
269 switch ((*rootp)->balance++) {
270 case -1: return True;
271 case 0: return False;
272 case 1: break;
273 default: tl_assert(0);
274 }
275 switch ((*rootp)->child[1]->balance) {
276 case 0:
277 avl_swl( rootp );
278 (*rootp)->balance = -1;
279 (*rootp)->child[0]->balance = 1;
280 return False;
281 case 1:
282 avl_swl( rootp );
283 (*rootp)->balance = 0;
284 (*rootp)->child[0]->balance = 0;
285 return True;
286 case -1:
287 break;
288 default:
289 tl_assert(0);
290 }
291 avl_swr( &((*rootp)->child[1]) );
292 avl_swl( rootp );
293 avl_nasty( *rootp );
294 return True;
295 }
296 }
297 else
298 if (cmpres < 0) {
299 /* remove from the right subtree */
300 AvlNode* right_subtree = (*rootp)->child[1];
301 tl_assert(right_subtree);
302 ch = avl_remove_wrk(&right_subtree, a, kCmp);
303 (*rootp)->child[1] = right_subtree;
304 if (ch) {
305 switch ((*rootp)->balance--) {
306 case 1: return True;
307 case 0: return False;
308 case -1: break;
309 default: tl_assert(0);
310 }
311 switch ((*rootp)->child[0]->balance) {
312 case 0:
313 avl_swr( rootp );
314 (*rootp)->balance = 1;
315 (*rootp)->child[1]->balance = -1;
316 return False;
317 case -1:
318 avl_swr( rootp );
319 (*rootp)->balance = 0;
320 (*rootp)->child[1]->balance = 0;
321 return True;
322 case 1:
323 break;
324 default:
325 tl_assert(0);
326 }
327 avl_swl( &((*rootp)->child[0]) );
328 avl_swr( rootp );
329 avl_nasty( *rootp );
330 return True;
331 }
332 }
333 else {
334 tl_assert(cmpres == 0);
335 tl_assert((*rootp)==a);
336 return avl_removeroot_wrk(rootp, kCmp);
337 }
338 return 0;
339}
340
341/* Remove the root of the AVL tree *rootp.
342 * Warning: dumps core if *rootp is empty
343 */
344static
345Bool avl_removeroot_wrk ( AvlNode** rootp,
346 Word(*kCmp)(Word,Word) )
347{
348 Bool ch;
349 AvlNode* a;
350 if (!(*rootp)->child[0]) {
351 if (!(*rootp)->child[1]) {
352 (*rootp) = 0;
353 return True;
354 }
355 (*rootp) = (*rootp)->child[1];
356 return True;
357 }
358 if (!(*rootp)->child[1]) {
359 (*rootp) = (*rootp)->child[0];
360 return True;
361 }
362 if ((*rootp)->balance < 0) {
363 /* remove from the left subtree */
364 a = (*rootp)->child[0];
365 while (a->child[1]) a = a->child[1];
366 } else {
367 /* remove from the right subtree */
368 a = (*rootp)->child[1];
369 while (a->child[0]) a = a->child[0];
370 }
371 ch = avl_remove_wrk(rootp, a, kCmp);
372 a->child[0] = (*rootp)->child[0];
373 a->child[1] = (*rootp)->child[1];
374 a->balance = (*rootp)->balance;
375 (*rootp) = a;
376 if(a->balance == 0) return ch;
377 return False;
378}
379
380static
381AvlNode* avl_find_node ( AvlNode* t, Word k, Word(*kCmp)(Word,Word) )
382{
383 if (kCmp) {
384 /* Boxed comparisons */
385 Word cmpres;
386 while (True) {
387 if (t == NULL) return NULL;
388 cmpres = kCmp(t->key, k);
389 if (cmpres > 0) t = t->child[0]; else
390 if (cmpres < 0) t = t->child[1]; else
391 return t;
392 }
393 } else {
394 /* Unboxed comparisons */
395 Word cmpres; /* signed */
396 UWord cmpresU; /* unsigned */
397 while (True) {
398 if (t == NULL) return NULL; /* unlikely ==> predictable */
399 cmpres = ((Word)t->key) - ((Word)k);
400 if (cmpres == 0) return t; /* unlikely ==> predictable */
401 cmpresU = (UWord)cmpres;
402 cmpresU >>=/*unsigned*/ (8 * sizeof(cmpres) - 1);
403 t = t->child[cmpresU];
404 }
405 }
406}
407
408// Clear the iterator stack.
409static void stackClear(WordFM* fm)
410{
411 Int i;
412 tl_assert(fm);
413 for (i = 0; i < WFM_STKMAX; i++) {
414 fm->nodeStack[i] = NULL;
415 fm->numStack[i] = 0;
416 }
417 fm->stackTop = 0;
418}
419
420// Push onto the iterator stack.
421static inline void stackPush(WordFM* fm, AvlNode* n, Int i)
422{
423 tl_assert(fm->stackTop < WFM_STKMAX);
424 tl_assert(1 <= i && i <= 3);
425 fm->nodeStack[fm->stackTop] = n;
426 fm-> numStack[fm->stackTop] = i;
427 fm->stackTop++;
428}
429
430// Pop from the iterator stack.
431static inline Bool stackPop(WordFM* fm, AvlNode** n, Int* i)
432{
433 tl_assert(fm->stackTop <= WFM_STKMAX);
434
435 if (fm->stackTop > 0) {
436 fm->stackTop--;
437 *n = fm->nodeStack[fm->stackTop];
438 *i = fm-> numStack[fm->stackTop];
439 tl_assert(1 <= *i && *i <= 3);
440 fm->nodeStack[fm->stackTop] = NULL;
441 fm-> numStack[fm->stackTop] = 0;
442 return True;
443 } else {
444 return False;
445 }
446}
447
448static
449AvlNode* avl_dopy ( AvlNode* nd,
450 Word(*dopyK)(Word),
451 Word(*dopyV)(Word),
452 void*(alloc_nofail)(SizeT) )
453{
454 AvlNode* nyu;
455 if (! nd)
456 return NULL;
457 nyu = alloc_nofail(sizeof(AvlNode));
458 tl_assert(nyu);
459
460 nyu->child[0] = nd->child[0];
461 nyu->child[1] = nd->child[1];
462 nyu->balance = nd->balance;
463
464 /* Copy key */
465 if (dopyK) {
466 nyu->key = dopyK( nd->key );
467 if (nd->key != 0 && nyu->key == 0)
468 return NULL; /* oom in key dcopy */
469 } else {
470 /* copying assumedly unboxed keys */
471 nyu->key = nd->key;
472 }
473
474 /* Copy val */
475 if (dopyV) {
476 nyu->val = dopyV( nd->val );
477 if (nd->val != 0 && nyu->val == 0)
478 return NULL; /* oom in val dcopy */
479 } else {
480 /* copying assumedly unboxed vals */
481 nyu->val = nd->val;
482 }
483
484 /* Copy subtrees */
485 if (nyu->child[0]) {
486 nyu->child[0] = avl_dopy( nyu->child[0], dopyK, dopyV, alloc_nofail );
487 if (! nyu->child[0])
488 return NULL;
489 }
490 if (nyu->child[1]) {
491 nyu->child[1] = avl_dopy( nyu->child[1], dopyK, dopyV, alloc_nofail );
492 if (! nyu->child[1])
493 return NULL;
494 }
495
496 return nyu;
497}
498
499/* Initialise a WordFM. */
500static void initFM ( WordFM* fm,
501 void* (*alloc_nofail)( SizeT ),
502 void (*dealloc)(void*),
503 Word (*kCmp)(Word,Word) )
504{
505 fm->root = 0;
506 fm->kCmp = kCmp;
507 fm->alloc_nofail = alloc_nofail;
508 fm->dealloc = dealloc;
509 fm->stackTop = 0;
510}
511
512/* --- Public interface functions --- */
513
514/* Allocate and Initialise a WordFM. */
515WordFM* HG_(newFM) ( void* (*alloc_nofail)( SizeT ),
516 void (*dealloc)(void*),
517 Word (*kCmp)(Word,Word) )
518{
519 WordFM* fm = alloc_nofail(sizeof(WordFM));
520 tl_assert(fm);
521 initFM(fm, alloc_nofail, dealloc, kCmp);
522 return fm;
523}
524
525static void avl_free ( AvlNode* nd,
526 void(*kFin)(Word),
527 void(*vFin)(Word),
528 void(*dealloc)(void*) )
529{
530 if (!nd)
531 return;
532 if (nd->child[0])
533 avl_free(nd->child[0], kFin, vFin, dealloc);
534 if (nd->child[1])
535 avl_free(nd->child[1], kFin, vFin, dealloc);
536 if (kFin)
537 kFin( nd->key );
538 if (vFin)
539 vFin( nd->val );
540 VG_(memset)(nd, 0, sizeof(AvlNode));
541 dealloc(nd);
542}
543
544/* Free up the FM. If kFin is non-NULL, it is applied to keys
545 before the FM is deleted; ditto with vFin for vals. */
546void HG_(deleteFM) ( WordFM* fm, void(*kFin)(Word), void(*vFin)(Word) )
547{
548 void(*dealloc)(void*) = fm->dealloc;
549 avl_free( fm->root, kFin, vFin, dealloc );
550 VG_(memset)(fm, 0, sizeof(WordFM) );
551 dealloc(fm);
552}
553
554/* Add (k,v) to fm. */
555void HG_(addToFM) ( WordFM* fm, Word k, Word v )
556{
557 MaybeWord oldV;
558 AvlNode* node;
559 node = fm->alloc_nofail( sizeof(struct _AvlNode) );
560 node->key = k;
561 node->val = v;
562 oldV.b = False;
563 oldV.w = 0;
564 avl_insert_wrk( &fm->root, &oldV, node, fm->kCmp );
565 //if (oldV.b && fm->vFin)
566 // fm->vFin( oldV.w );
567 if (oldV.b)
568 fm->dealloc(node);
569}
570
571// Delete key from fm, returning associated key and val if found
572Bool HG_(delFromFM) ( WordFM* fm,
573 /*OUT*/Word* oldK, /*OUT*/Word* oldV, Word key )
574{
575 AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
576 if (node) {
577 avl_remove_wrk( &fm->root, node, fm->kCmp );
578 if (oldK)
579 *oldK = node->key;
580 if (oldV)
581 *oldV = node->val;
582 fm->dealloc(node);
583 return True;
584 } else {
585 return False;
586 }
587}
588
589// Look up in fm, assigning found key & val at spec'd addresses
590Bool HG_(lookupFM) ( WordFM* fm,
591 /*OUT*/Word* keyP, /*OUT*/Word* valP, Word key )
592{
593 AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
594 if (node) {
595 if (keyP)
596 *keyP = node->key;
597 if (valP)
598 *valP = node->val;
599 return True;
600 } else {
601 return False;
602 }
603}
604
605Word HG_(sizeFM) ( WordFM* fm )
606{
607 // Hmm, this is a bad way to do this
608 return fm->root ? size_avl_nonNull( fm->root ) : 0;
609}
610
611// set up FM for iteration
612void HG_(initIterFM) ( WordFM* fm )
613{
614 tl_assert(fm);
615 stackClear(fm);
616 if (fm->root)
617 stackPush(fm, fm->root, 1);
618}
619
620// get next key/val pair. Will tl_assert if fm has been modified
621// or looked up in since initIterFM was called.
622Bool HG_(nextIterFM) ( WordFM* fm, /*OUT*/Word* pKey, /*OUT*/Word* pVal )
623{
624 Int i = 0;
625 AvlNode* n = NULL;
626
627 tl_assert(fm);
628
629 // This in-order traversal requires each node to be pushed and popped
630 // three times. These could be avoided by updating nodes in-situ on the
631 // top of the stack, but the push/pop cost is so small that it's worth
632 // keeping this loop in this simpler form.
633 while (stackPop(fm, &n, &i)) {
634 switch (i) {
635 case 1: case_1:
636 stackPush(fm, n, 2);
637 /* if (n->child[0]) stackPush(fm, n->child[0], 1); */
638 if (n->child[0]) { n = n->child[0]; goto case_1; }
639 break;
640 case 2:
641 stackPush(fm, n, 3);
642 if (pKey) *pKey = n->key;
643 if (pVal) *pVal = n->val;
644 return True;
645 case 3:
646 /* if (n->child[1]) stackPush(fm, n->child[1], 1); */
647 if (n->child[1]) { n = n->child[1]; goto case_1; }
648 break;
649 default:
650 tl_assert(0);
651 }
652 }
653
654 // Stack empty, iterator is exhausted, return NULL
655 return False;
656}
657
658// clear the I'm iterating flag
659void HG_(doneIterFM) ( WordFM* fm )
660{
661}
662
663WordFM* HG_(dopyFM) ( WordFM* fm, Word(*dopyK)(Word), Word(*dopyV)(Word) )
664{
665 WordFM* nyu;
666
667 /* can't clone the fm whilst iterating on it */
668 tl_assert(fm->stackTop == 0);
669
670 nyu = fm->alloc_nofail( sizeof(WordFM) );
671 tl_assert(nyu);
672
673 *nyu = *fm;
674
675 fm->stackTop = 0;
676 VG_(memset)(fm->nodeStack, 0, sizeof(fm->nodeStack));
677 VG_(memset)(fm->numStack, 0, sizeof(fm->numStack));
678
679 if (nyu->root) {
680 nyu->root = avl_dopy( nyu->root, dopyK, dopyV, fm->alloc_nofail );
681 if (! nyu->root)
682 return NULL;
683 }
684
685 return nyu;
686}
687
688//------------------------------------------------------------------//
689//--- end WordFM ---//
690//--- Implementation ---//
691//------------------------------------------------------------------//
692
693//------------------------------------------------------------------//
694//--- WordBag (unboxed words only) ---//
695//--- Implementation ---//
696//------------------------------------------------------------------//
697
698/* A trivial container, to make it opaque. */
699struct _WordBag {
700 WordFM* fm;
701};
702
703WordBag* HG_(newBag) ( void* (*alloc_nofail)( SizeT ),
704 void (*dealloc)(void*) )
705{
706 WordBag* bag = alloc_nofail(sizeof(WordBag));
707 bag->fm = HG_(newFM)( alloc_nofail, dealloc, NULL );
708 return bag;
709}
710
711void HG_(deleteBag) ( WordBag* bag )
712{
713 void (*dealloc)(void*) = bag->fm->dealloc;
714 HG_(deleteFM)( bag->fm, NULL, NULL );
715 VG_(memset)(bag, 0, sizeof(WordBag));
716 dealloc(bag);
717}
718
719void HG_(addToBag)( WordBag* bag, Word w )
720{
721 Word key, count;
722 if (HG_(lookupFM)(bag->fm, &key, &count, w)) {
723 tl_assert(key == w);
724 tl_assert(count >= 1);
725 HG_(addToFM)(bag->fm, w, count+1);
726 } else {
727 HG_(addToFM)(bag->fm, w, 1);
728 }
729}
730
731Word HG_(elemBag) ( WordBag* bag, Word w )
732{
733 Word key, count;
734 if (HG_(lookupFM)( bag->fm, &key, &count, w)) {
735 tl_assert(key == w);
736 tl_assert(count >= 1);
737 return count;
738 } else {
739 return 0;
740 }
741}
742
743Word HG_(sizeUniqueBag) ( WordBag* bag )
744{
745 return HG_(sizeFM)( bag->fm );
746}
747
748static Word sizeTotalBag_wrk ( AvlNode* nd )
749{
750 /* unchecked pre: nd is non-NULL */
751 Word w = nd->val;
752 tl_assert(w >= 1);
753 if (nd->child[0])
754 w += sizeTotalBag_wrk(nd->child[0]);
755 if (nd->child[1])
756 w += sizeTotalBag_wrk(nd->child[1]);
757 return w;
758}
759Word HG_(sizeTotalBag)( WordBag* bag )
760{
761 if (bag->fm->root)
762 return sizeTotalBag_wrk(bag->fm->root);
763 else
764 return 0;
765}
766
767Bool HG_(delFromBag)( WordBag* bag, Word w )
768{
769 Word key, count;
770 if (HG_(lookupFM)(bag->fm, &key, &count, w)) {
771 tl_assert(key == w);
772 tl_assert(count >= 1);
773 if (count > 1) {
774 HG_(addToFM)(bag->fm, w, count-1);
775 } else {
776 tl_assert(count == 1);
777 HG_(delFromFM)( bag->fm, NULL, NULL, w );
778 }
779 return True;
780 } else {
781 return False;
782 }
783}
784
785Bool HG_(isEmptyBag)( WordBag* bag )
786{
787 return HG_(sizeFM)(bag->fm) == 0;
788}
789
790Bool HG_(isSingletonTotalBag)( WordBag* bag )
791{
792 AvlNode* nd;
793 if (HG_(sizeFM)(bag->fm) != 1)
794 return False;
795 nd = bag->fm->root;
796 tl_assert(nd);
797 tl_assert(!nd->child[0]);
798 tl_assert(!nd->child[1]);
799 return nd->val == 1;
800}
801
802Word HG_(anyElementOfBag)( WordBag* bag )
803{
804 /* Return an arbitrarily chosen element in the bag. We might as
805 well return the one at the root of the underlying AVL tree. */
806 AvlNode* nd = bag->fm->root;
807 tl_assert(nd); /* if this fails, 'bag' is empty - caller is in error. */
808 tl_assert(nd->val >= 1);
809 return nd->key;
810}
811
812void HG_(initIterBag)( WordBag* bag )
813{
814 HG_(initIterFM)(bag->fm);
815}
816
817Bool HG_(nextIterBag)( WordBag* bag, /*OUT*/Word* pVal, /*OUT*/Word* pCount )
818{
819 return HG_(nextIterFM)( bag->fm, pVal, pCount );
820}
821
822void HG_(doneIterBag)( WordBag* bag )
823{
824 HG_(doneIterFM)( bag->fm );
825}
826
827//------------------------------------------------------------------//
828//--- end WordBag (unboxed words only) ---//
829//--- Implementation ---//
830//------------------------------------------------------------------//
831
832/*--------------------------------------------------------------------*/
833/*--- end hg_wordfm.c ---*/
834/*--------------------------------------------------------------------*/