2 /*--------------------------------------------------------------------*/
3 /*--- An AVL tree based finite map for word keys and word values. ---*/
4 /*--- Inspired by Haskell's "FiniteMap" library. ---*/
6 /*--------------------------------------------------------------------*/
9 This file is part of Valgrind, a dynamic binary instrumentation
12 Copyright (C) 2007-2017 Julian Seward
15 This code is based on previous work by Nicholas Nethercote
16 (coregrind/m_oset.c) which is
18 Copyright (C) 2005-2017 Nicholas Nethercote
21 which in turn was derived partially from:
24 Copyright (C) 2000,2002 Daniel Nagy
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.
32 (taken from libavl-0.4/debian/copyright)
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.
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.
44 You should have received a copy of the GNU General Public License
45 along with this program; if not, see <http://www.gnu.org/licenses/>.
47 The GNU General Public License is contained in the file COPYING.
50 #include "pub_core_basics.h"
51 #include "pub_core_libcassert.h"
52 #include "pub_core_libcbase.h"
53 #include "pub_core_wordfm.h" /* self */
56 //------------------------------------------------------------------//
58 //--- Implementation ---//
59 //------------------------------------------------------------------//
61 /* One element of the AVL tree */
66 struct _AvlNode
* child
[2]; /* [0] is left subtree, [1] is right */
67 Char balance
; /* do not make this unsigned */
78 #define WFM_STKMAX 32 // At most 2**32 entries can be iterated over
82 void* (*alloc_nofail
)( const HChar
*, SizeT
);
84 void (*dealloc
)(void*);
85 Word (*kCmp
)(UWord
,UWord
);
86 AvlNode
* nodeStack
[WFM_STKMAX
]; // Iterator node stack
87 Int numStack
[WFM_STKMAX
]; // Iterator num stack
88 Int stackTop
; // Iterator stack pointer, one past end
92 static Bool
avl_removeroot_wrk(AvlNode
** t
, Word(*kCmp
)(UWord
,UWord
));
94 /* Swing to the left. Warning: no balance maintenance. */
95 static void avl_swl ( AvlNode
** root
)
98 AvlNode
* b
= a
->child
[1];
100 a
->child
[1] = b
->child
[0];
104 /* Swing to the right. Warning: no balance maintenance. */
105 static void avl_swr ( AvlNode
** root
)
108 AvlNode
* b
= a
->child
[0];
110 a
->child
[0] = b
->child
[1];
114 /* Balance maintenance after especially nasty swings. */
115 static void avl_nasty ( AvlNode
* root
)
117 switch (root
->balance
) {
119 root
->child
[0]->balance
= 0;
120 root
->child
[1]->balance
= 1;
123 root
->child
[0]->balance
= -1;
124 root
->child
[1]->balance
= 0;
127 root
->child
[0]->balance
= 0;
128 root
->child
[1]->balance
= 0;
136 /* Find size of a non-NULL tree. */
137 static UWord
size_avl_nonNull ( const AvlNode
* nd
)
139 return 1 + (nd
->child
[0] ? size_avl_nonNull(nd
->child
[0]) : 0)
140 + (nd
->child
[1] ? size_avl_nonNull(nd
->child
[1]) : 0);
143 /* Unsignedly compare w1 and w2. If w1 < w2, produce a negative
144 number; if w1 > w2 produce a positive number, and if w1 == w2
146 static inline Word
cmp_unsigned_Words ( UWord w1
, UWord w2
) {
147 if (w1
< w2
) return -1;
148 if (w1
> w2
) return 1;
152 /* Insert element a into the AVL tree t. Returns True if the depth of
153 the tree has grown. If element with that key is already present,
154 just copy a->val to existing node, first returning old ->val field
155 of existing node in *oldV, so that the caller can finalize it
159 Bool
avl_insert_wrk ( AvlNode
** rootp
,
160 /*OUT*/MaybeWord
* oldV
,
162 Word (*kCmp
)(UWord
,UWord
) )
172 /* insert into an empty tree? */
178 cmpres
= kCmp
? /*boxed*/ kCmp( (*rootp
)->key
, a
->key
)
179 : /*unboxed*/ cmp_unsigned_Words( (UWord
)(*rootp
)->key
,
183 /* insert into the left subtree */
184 if ((*rootp
)->child
[0]) {
185 AvlNode
* left_subtree
= (*rootp
)->child
[0];
186 if (avl_insert_wrk(&left_subtree
, oldV
, a
, kCmp
)) {
187 switch ((*rootp
)->balance
--) {
188 case 1: return False
;
191 default: vg_assert(0);
193 if ((*rootp
)->child
[0]->balance
< 0) {
195 (*rootp
)->balance
= 0;
196 (*rootp
)->child
[1]->balance
= 0;
198 avl_swl( &((*rootp
)->child
[0]) );
203 (*rootp
)->child
[0] = left_subtree
;
207 (*rootp
)->child
[0] = a
;
208 if ((*rootp
)->balance
--)
212 vg_assert(0);/*NOTREACHED*/
216 /* insert into the right subtree */
217 if ((*rootp
)->child
[1]) {
218 AvlNode
* right_subtree
= (*rootp
)->child
[1];
219 if (avl_insert_wrk(&right_subtree
, oldV
, a
, kCmp
)) {
220 switch((*rootp
)->balance
++){
221 case -1: return False
;
224 default: vg_assert(0);
226 if ((*rootp
)->child
[1]->balance
> 0) {
228 (*rootp
)->balance
= 0;
229 (*rootp
)->child
[0]->balance
= 0;
231 avl_swr( &((*rootp
)->child
[1]) );
236 (*rootp
)->child
[1] = right_subtree
;
240 (*rootp
)->child
[1] = a
;
241 if ((*rootp
)->balance
++)
245 vg_assert(0);/*NOTREACHED*/
248 /* cmpres == 0, a duplicate - replace the val, but don't
249 incorporate the node in the tree */
251 oldV
->w
= (*rootp
)->val
;
252 (*rootp
)->val
= a
->val
;
257 /* Remove an element a from the AVL tree t. a must be part of
258 the tree. Returns True if the depth of the tree has shrunk.
261 Bool
avl_remove_wrk ( AvlNode
** rootp
,
263 Word(*kCmp
)(UWord
,UWord
) )
267 cmpres
= kCmp
? /*boxed*/ kCmp( (*rootp
)->key
, a
->key
)
268 : /*unboxed*/ cmp_unsigned_Words( (UWord
)(*rootp
)->key
,
272 /* remove from the left subtree */
273 AvlNode
* left_subtree
= (*rootp
)->child
[0];
274 vg_assert(left_subtree
);
275 ch
= avl_remove_wrk(&left_subtree
, a
, kCmp
);
276 (*rootp
)->child
[0]=left_subtree
;
278 switch ((*rootp
)->balance
++) {
279 case -1: return True
;
280 case 0: return False
;
282 default: vg_assert(0);
284 switch ((*rootp
)->child
[1]->balance
) {
287 (*rootp
)->balance
= -1;
288 (*rootp
)->child
[0]->balance
= 1;
292 (*rootp
)->balance
= 0;
293 (*rootp
)->child
[0]->balance
= 0;
300 avl_swr( &((*rootp
)->child
[1]) );
308 /* remove from the right subtree */
309 AvlNode
* right_subtree
= (*rootp
)->child
[1];
310 vg_assert(right_subtree
);
311 ch
= avl_remove_wrk(&right_subtree
, a
, kCmp
);
312 (*rootp
)->child
[1] = right_subtree
;
314 switch ((*rootp
)->balance
--) {
316 case 0: return False
;
318 default: vg_assert(0);
320 switch ((*rootp
)->child
[0]->balance
) {
323 (*rootp
)->balance
= 1;
324 (*rootp
)->child
[1]->balance
= -1;
328 (*rootp
)->balance
= 0;
329 (*rootp
)->child
[1]->balance
= 0;
336 avl_swl( &((*rootp
)->child
[0]) );
343 vg_assert(cmpres
== 0);
344 vg_assert((*rootp
)==a
);
345 return avl_removeroot_wrk(rootp
, kCmp
);
350 /* Remove the root of the AVL tree *rootp.
351 * Warning: dumps core if *rootp is empty
354 Bool
avl_removeroot_wrk ( AvlNode
** rootp
,
355 Word(*kCmp
)(UWord
,UWord
) )
359 if (!(*rootp
)->child
[0]) {
360 if (!(*rootp
)->child
[1]) {
364 (*rootp
) = (*rootp
)->child
[1];
367 if (!(*rootp
)->child
[1]) {
368 (*rootp
) = (*rootp
)->child
[0];
371 if ((*rootp
)->balance
< 0) {
372 /* remove from the left subtree */
373 a
= (*rootp
)->child
[0];
374 while (a
->child
[1]) a
= a
->child
[1];
376 /* remove from the right subtree */
377 a
= (*rootp
)->child
[1];
378 while (a
->child
[0]) a
= a
->child
[0];
380 ch
= avl_remove_wrk(rootp
, a
, kCmp
);
381 a
->child
[0] = (*rootp
)->child
[0];
382 a
->child
[1] = (*rootp
)->child
[1];
383 a
->balance
= (*rootp
)->balance
;
385 if(a
->balance
== 0) return ch
;
390 AvlNode
* avl_find_node ( AvlNode
* t
, Word k
, Word(*kCmp
)(UWord
,UWord
) )
393 /* Boxed comparisons */
396 if (t
== NULL
) return NULL
;
397 cmpresS
= kCmp(t
->key
, k
);
398 if (cmpresS
> 0) t
= t
->child
[0]; else
399 if (cmpresS
< 0) t
= t
->child
[1]; else
403 /* Unboxed comparisons */
404 Word cmpresS
; /* signed */
405 UWord cmpresU
; /* unsigned */
407 if (t
== NULL
) return NULL
; /* unlikely ==> predictable */
408 cmpresS
= cmp_unsigned_Words( (UWord
)t
->key
, (UWord
)k
);
409 if (cmpresS
== 0) return t
; /* unlikely ==> predictable */
410 cmpresU
= (UWord
)cmpresS
;
411 cmpresU
>>=/*unsigned*/ (8 * sizeof(cmpresU
) - 1);
412 t
= t
->child
[cmpresU
];
418 Bool
avl_find_bounds ( const AvlNode
* t
,
419 /*OUT*/UWord
* kMinP
, /*OUT*/UWord
* vMinP
,
420 /*OUT*/UWord
* kMaxP
, /*OUT*/UWord
* vMaxP
,
421 UWord minKey
, UWord minVal
,
422 UWord maxKey
, UWord maxVal
,
424 Word(*kCmp
)(UWord
,UWord
) )
426 UWord kLowerBound
= minKey
;
427 UWord vLowerBound
= minVal
;
428 UWord kUpperBound
= maxKey
;
429 UWord vUpperBound
= maxVal
;
431 Word cmpresS
= kCmp
? kCmp(t
->key
, key
)
432 : cmp_unsigned_Words(t
->key
, key
);
434 kLowerBound
= t
->key
;
435 vLowerBound
= t
->val
;
440 kUpperBound
= t
->key
;
441 vUpperBound
= t
->val
;
445 /* We should never get here. If we do, it means the given key
446 is actually present in the tree, which means the original
447 call was invalid -- an error on the caller's part, and we
448 cannot give any meaningful values for the bounds. (Well,
449 maybe we could, but we're not gonna. Ner!) */
452 if (kMinP
) *kMinP
= kLowerBound
;
453 if (vMinP
) *vMinP
= vLowerBound
;
454 if (kMaxP
) *kMaxP
= kUpperBound
;
455 if (vMaxP
) *vMaxP
= vUpperBound
;
459 // Clear the iterator stack.
460 static void stackClear(WordFM
* fm
)
464 for (i
= 0; i
< WFM_STKMAX
; i
++) {
465 fm
->nodeStack
[i
] = NULL
;
471 // Push onto the iterator stack.
472 static inline void stackPush(WordFM
* fm
, AvlNode
* n
, Int i
)
474 vg_assert(fm
->stackTop
< WFM_STKMAX
);
475 vg_assert(1 <= i
&& i
<= 3);
476 fm
->nodeStack
[fm
->stackTop
] = n
;
477 fm
-> numStack
[fm
->stackTop
] = i
;
481 // Pop from the iterator stack.
482 static inline Bool
stackPop(WordFM
* fm
, AvlNode
** n
, Int
* i
)
484 vg_assert(fm
->stackTop
<= WFM_STKMAX
);
486 if (fm
->stackTop
> 0) {
488 *n
= fm
->nodeStack
[fm
->stackTop
];
489 *i
= fm
-> numStack
[fm
->stackTop
];
490 vg_assert(1 <= *i
&& *i
<= 3);
491 fm
->nodeStack
[fm
->stackTop
] = NULL
;
492 fm
-> numStack
[fm
->stackTop
] = 0;
500 AvlNode
* avl_dopy ( const AvlNode
* nd
,
501 UWord(*dopyK
)(UWord
),
502 UWord(*dopyV
)(UWord
),
503 void*(alloc_nofail
)(const HChar
*,SizeT
),
508 vg_assert(nd
!= NULL
);
510 nyu
= alloc_nofail(cc
, sizeof(AvlNode
));
512 nyu
->child
[0] = nd
->child
[0];
513 nyu
->child
[1] = nd
->child
[1];
514 nyu
->balance
= nd
->balance
;
518 nyu
->key
= dopyK( nd
->key
);
520 /* copying assumedly unboxed keys */
526 nyu
->val
= dopyV( nd
->val
);
528 /* copying assumedly unboxed vals */
534 nyu
->child
[0] = avl_dopy( nyu
->child
[0], dopyK
, dopyV
,
538 nyu
->child
[1] = avl_dopy( nyu
->child
[1], dopyK
, dopyV
,
545 /* Initialise a WordFM. */
546 static void initFM ( WordFM
* fm
,
547 void* (*alloc_nofail
)( const HChar
*, SizeT
),
549 void (*dealloc
)(void*),
550 Word (*kCmp
)(UWord
,UWord
) )
554 fm
->alloc_nofail
= alloc_nofail
;
556 fm
->dealloc
= dealloc
;
560 /* --- Public interface functions --- */
562 /* Allocate and initialise a WordFM. If kCmp is non-NULL, elements in
563 the set are ordered according to the ordering specified by kCmp,
564 which becomes obvious if you use VG_(initIterFM),
565 VG_(initIterAtFM), VG_(nextIterFM), VG_(doneIterFM) to iterate over
566 sections of the map, or the whole thing. If kCmp is NULL then the
567 ordering used is unsigned word ordering (UWord) on the key
569 WordFM
* VG_(newFM
) ( void* (*alloc_nofail
)( const HChar
*, SizeT
),
571 void (*dealloc
)(void*),
572 Word (*kCmp
)(UWord
,UWord
) )
574 WordFM
* fm
= alloc_nofail(cc
, sizeof(WordFM
));
575 initFM(fm
, alloc_nofail
, cc
, dealloc
, kCmp
);
579 static void avl_free ( AvlNode
* nd
,
582 void(*dealloc
)(void*) )
587 avl_free(nd
->child
[0], kFin
, vFin
, dealloc
);
589 avl_free(nd
->child
[1], kFin
, vFin
, dealloc
);
594 VG_(memset
)(nd
, 0, sizeof(AvlNode
));
598 /* Free up the FM. If kFin is non-NULL, it is applied to keys
599 before the FM is deleted; ditto with vFin for vals. */
600 void VG_(deleteFM
) ( WordFM
* fm
, void(*kFin
)(UWord
), void(*vFin
)(UWord
) )
602 void(*dealloc
)(void*) = fm
->dealloc
;
603 avl_free( fm
->root
, kFin
, vFin
, dealloc
);
604 VG_(memset
)(fm
, 0, sizeof(WordFM
) );
608 /* Add (k,v) to fm. */
609 Bool
VG_(addToFM
) ( WordFM
* fm
, UWord k
, UWord v
)
613 node
= fm
->alloc_nofail( fm
->cc
, sizeof(AvlNode
) );
618 avl_insert_wrk( &fm
->root
, &oldV
, node
, fm
->kCmp
);
619 //if (oldV.b && fm->vFin)
620 // fm->vFin( oldV.w );
626 // Delete key from fm, returning associated key and val if found
627 Bool
VG_(delFromFM
) ( WordFM
* fm
,
628 /*OUT*/UWord
* oldK
, /*OUT*/UWord
* oldV
, UWord key
)
630 AvlNode
* node
= avl_find_node( fm
->root
, key
, fm
->kCmp
);
632 avl_remove_wrk( &fm
->root
, node
, fm
->kCmp
);
644 // Look up in fm, assigning found key & val at spec'd addresses
645 Bool
VG_(lookupFM
) ( const WordFM
* fm
,
646 /*OUT*/UWord
* keyP
, /*OUT*/UWord
* valP
, UWord key
)
648 AvlNode
* node
= avl_find_node( fm
->root
, key
, fm
->kCmp
);
660 // See comment in pub_tool_wordfm.h for explanation
661 Bool
VG_(findBoundsFM
)( const WordFM
* fm
,
662 /*OUT*/UWord
* kMinP
, /*OUT*/UWord
* vMinP
,
663 /*OUT*/UWord
* kMaxP
, /*OUT*/UWord
* vMaxP
,
664 UWord minKey
, UWord minVal
,
665 UWord maxKey
, UWord maxVal
,
668 /* really we should assert that minKey <= key <= maxKey,
669 where <= is as defined by fm->kCmp. */
670 return avl_find_bounds( fm
->root
, kMinP
, vMinP
,
677 // See comment in pub_tool_wordfm.h for performance warning
678 UWord
VG_(sizeFM
) ( const WordFM
* fm
)
680 // Hmm, this is a bad way to do this
681 return fm
->root
? size_avl_nonNull( fm
->root
) : 0;
684 // NB UNTESTED! TEST BEFORE USE!
685 //Bool VG_(isEmptyFM)( const WordFM* fm )
687 // return fm->root ? False : True;
690 // set up FM for iteration
691 void VG_(initIterFM
) ( WordFM
* fm
)
696 stackPush(fm
, fm
->root
, 1);
699 // set up FM for iteration so that the first key subsequently produced
700 // by VG_(nextIterFM) is the smallest key in the map >= start_at.
701 // Naturally ">=" is defined by the comparison function supplied to
702 // VG_(newFM), as documented above.
703 void VG_(initIterAtFM
) ( WordFM
* fm
, UWord start_at
)
707 Word cmpresS
; /* signed */
708 UWord cmpresU
; /* unsigned */
717 // We need to do regular search and fill in the stack.
721 if (t
== NULL
) return;
724 = fm
->kCmp
? /*boxed*/ fm
->kCmp( t
->key
, start_at
)
725 : /*unboxed*/ cmp_unsigned_Words( t
->key
, start_at
);
728 // We found the exact key -- we are done.
729 // The iteration should start with this node.
731 // The stack now looks like {2, 2, ... ,2, 2}
734 cmpresU
= (UWord
)cmpresS
;
735 cmpresU
>>=/*unsigned*/ (8 * sizeof(cmpresU
) - 1);
737 // Push this node only if we go to the left child.
740 t
= t
->child
[cmpresU
];
742 if (stackPop(fm
, &n
, &i
)) {
743 // If we've pushed something to stack and did not find the exact key,
744 // we must fix the top element of stack.
747 // the stack looks like {2, 2, ..., 2, 3}
751 // get next key/val pair. Will vg_assert if fm has been modified
752 // or looked up in since initIter{,At}FM was called.
753 Bool
VG_(nextIterFM
) ( WordFM
* fm
, /*OUT*/UWord
* pKey
, /*OUT*/UWord
* pVal
)
760 // This in-order traversal requires each node to be pushed and popped
761 // three times. These could be avoided by updating nodes in-situ on the
762 // top of the stack, but the push/pop cost is so small that it's worth
763 // keeping this loop in this simpler form.
764 while (stackPop(fm
, &n
, &i
)) {
768 /* if (n->child[0]) stackPush(fm, n->child[0], 1); */
769 if (n
->child
[0]) { n
= n
->child
[0]; goto case_1
; }
773 if (pKey
) *pKey
= n
->key
;
774 if (pVal
) *pVal
= n
->val
;
777 /* if (n->child[1]) stackPush(fm, n->child[1], 1); */
778 if (n
->child
[1]) { n
= n
->child
[1]; goto case_1
; }
785 // Stack empty, iterator is exhausted, return NULL
789 // Finish an FM iteration
790 void VG_(doneIterFM
) ( WordFM
* fm
)
794 WordFM
* VG_(dopyFM
) ( WordFM
* fm
, UWord(*dopyK
)(UWord
),
795 UWord(*dopyV
)(UWord
) )
799 /* can't clone the fm whilst iterating on it */
800 vg_assert(fm
->stackTop
== 0);
802 nyu
= fm
->alloc_nofail( fm
->cc
, sizeof(WordFM
) );
807 VG_(memset
)(fm
->nodeStack
, 0, sizeof(fm
->nodeStack
));
808 VG_(memset
)(fm
->numStack
, 0, sizeof(fm
->numStack
));
811 nyu
->root
= avl_dopy( nyu
->root
, dopyK
, dopyV
,
812 fm
->alloc_nofail
, fm
->cc
);
820 //------------------------------------------------------------------//
821 //--- end WordFM ---//
822 //--- Implementation ---//
823 //------------------------------------------------------------------//
825 //------------------------------------------------------------------//
826 //--- WordBag (unboxed words only) ---//
827 //--- Implementation ---//
828 //------------------------------------------------------------------//
830 /* A trivial container, to make it opaque. */
835 WordBag
* VG_(newBag
) ( void* (*alloc_nofail
)( const HChar
*, SizeT
),
837 void (*dealloc
)(void*) )
839 WordBag
* bag
= alloc_nofail(cc
, sizeof(WordBag
));
840 bag
->fm
= VG_(newFM
)( alloc_nofail
, cc
, dealloc
, NULL
);
844 void VG_(deleteBag
) ( WordBag
* bag
)
846 void (*dealloc
)(void*) = bag
->fm
->dealloc
;
847 VG_(deleteFM
)( bag
->fm
, NULL
, NULL
);
848 VG_(memset
)(bag
, 0, sizeof(WordBag
));
852 void VG_(addToBag
)( WordBag
* bag
, UWord w
)
855 if (VG_(lookupFM
)(bag
->fm
, &key
, &count
, w
)) {
857 vg_assert(count
>= 1);
858 VG_(addToFM
)(bag
->fm
, w
, count
+1);
860 VG_(addToFM
)(bag
->fm
, w
, 1);
864 UWord
VG_(elemBag
) ( const WordBag
* bag
, UWord w
)
867 if (VG_(lookupFM
)( bag
->fm
, &key
, &count
, w
)) {
869 vg_assert(count
>= 1);
876 UWord
VG_(sizeUniqueBag
) ( const WordBag
* bag
)
878 return VG_(sizeFM
)( bag
->fm
);
881 static UWord
sizeTotalBag_wrk ( const AvlNode
* nd
)
883 /* unchecked pre: nd is non-NULL */
887 w
+= sizeTotalBag_wrk(nd
->child
[0]);
889 w
+= sizeTotalBag_wrk(nd
->child
[1]);
892 UWord
VG_(sizeTotalBag
)( const WordBag
* bag
)
895 return sizeTotalBag_wrk(bag
->fm
->root
);
900 Bool
VG_(delFromBag
)( WordBag
* bag
, UWord w
)
903 if (VG_(lookupFM
)(bag
->fm
, &key
, &count
, w
)) {
905 vg_assert(count
>= 1);
907 VG_(addToFM
)(bag
->fm
, w
, count
-1);
909 vg_assert(count
== 1);
910 VG_(delFromFM
)( bag
->fm
, NULL
, NULL
, w
);
918 Bool
VG_(isEmptyBag
)( const WordBag
* bag
)
920 return VG_(sizeFM
)(bag
->fm
) == 0;
923 Bool
VG_(isSingletonTotalBag
)( const WordBag
* bag
)
926 if (VG_(sizeFM
)(bag
->fm
) != 1)
930 vg_assert(!nd
->child
[0]);
931 vg_assert(!nd
->child
[1]);
935 UWord
VG_(anyElementOfBag
)( const WordBag
* bag
)
937 /* Return an arbitrarily chosen element in the bag. We might as
938 well return the one at the root of the underlying AVL tree. */
939 AvlNode
* nd
= bag
->fm
->root
;
940 vg_assert(nd
); /* if this fails, 'bag' is empty - caller is in error. */
941 vg_assert(nd
->val
>= 1);
945 void VG_(initIterBag
)( WordBag
* bag
)
947 VG_(initIterFM
)(bag
->fm
);
950 Bool
VG_(nextIterBag
)( WordBag
* bag
, /*OUT*/UWord
* pVal
, /*OUT*/UWord
* pCount
)
952 return VG_(nextIterFM
)( bag
->fm
, pVal
, pCount
);
955 void VG_(doneIterBag
)( WordBag
* bag
)
957 VG_(doneIterFM
)( bag
->fm
);
960 //------------------------------------------------------------------//
961 //--- end WordBag (unboxed words only) ---//
962 //--- Implementation ---//
963 //------------------------------------------------------------------//
965 /*--------------------------------------------------------------------*/
966 /*--- end m_wordfm.c ---*/
967 /*--------------------------------------------------------------------*/