1
2 /*--------------------------------------------------------------------*/
3 /*--- An AVL tree based finite map for word keys and word values. ---*/
4 /*--- Inspired by Haskell's "FiniteMap" library. ---*/
5 /*--- m_wordfm.c ---*/
6 /*--------------------------------------------------------------------*/
7
8 /*
9 This file is part of Valgrind, a dynamic binary instrumentation
10 framework.
11
12 Copyright (C) 2007-2013 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-2013 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_core_basics.h"
53 #include "pub_core_libcassert.h"
54 #include "pub_core_libcbase.h"
55 #include "pub_core_wordfm.h" /* self */
56
57
58 //------------------------------------------------------------------//
59 //--- WordFM ---//
60 //--- Implementation ---//
61 //------------------------------------------------------------------//
62
63 /* One element of the AVL tree */
64 typedef
65 struct _AvlNode {
66 UWord key;
67 UWord val;
68 struct _AvlNode* child[2]; /* [0] is left subtree, [1] is right */
69 Char balance; /* do not make this unsigned */
70 }
71 AvlNode;
72
73 typedef
74 struct {
75 UWord w;
76 Bool b;
77 }
78 MaybeWord;
79
80 #define WFM_STKMAX 32 // At most 2**32 entries can be iterated over
81
82 struct _WordFM {
83 AvlNode* root;
84 void* (*alloc_nofail)( const HChar*, SizeT );
85 const HChar* cc;
86 void (*dealloc)(void*);
87 Word (*kCmp)(UWord,UWord);
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 */
94 static Bool avl_removeroot_wrk(AvlNode** t, Word(*kCmp)(UWord,UWord));
95
96 /* Swing to the left. Warning: no balance maintainance. */
avl_swl(AvlNode ** root)97 static 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. */
avl_swr(AvlNode ** root)107 static 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. */
avl_nasty(AvlNode * root)117 static 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. */
size_avl_nonNull(AvlNode * nd)139 static UWord 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 /* Unsignedly compare w1 and w2. If w1 < w2, produce a negative
146 number; if w1 > w2 produce a positive number, and if w1 == w2
147 produce zero. */
cmp_unsigned_Words(UWord w1,UWord w2)148 static inline Word cmp_unsigned_Words ( UWord w1, UWord w2 ) {
149 if (w1 < w2) return -1;
150 if (w1 > w2) return 1;
151 return 0;
152 }
153
154 /* Insert element a into the AVL tree t. Returns True if the depth of
155 the tree has grown. If element with that key is already present,
156 just copy a->val to existing node, first returning old ->val field
157 of existing node in *oldV, so that the caller can finalize it
158 however it wants.
159 */
160 static
avl_insert_wrk(AvlNode ** rootp,MaybeWord * oldV,AvlNode * a,Word (* kCmp)(UWord,UWord))161 Bool avl_insert_wrk ( AvlNode** rootp,
162 /*OUT*/MaybeWord* oldV,
163 AvlNode* a,
164 Word (*kCmp)(UWord,UWord) )
165 {
166 Word cmpres;
167
168 /* initialize */
169 a->child[0] = 0;
170 a->child[1] = 0;
171 a->balance = 0;
172 oldV->b = False;
173
174 /* insert into an empty tree? */
175 if (!(*rootp)) {
176 (*rootp) = a;
177 return True;
178 }
179
180 cmpres = kCmp ? /*boxed*/ kCmp( (*rootp)->key, a->key )
181 : /*unboxed*/ cmp_unsigned_Words( (UWord)(*rootp)->key,
182 (UWord)a->key );
183
184 if (cmpres > 0) {
185 /* insert into the left subtree */
186 if ((*rootp)->child[0]) {
187 AvlNode* left_subtree = (*rootp)->child[0];
188 if (avl_insert_wrk(&left_subtree, oldV, a, kCmp)) {
189 switch ((*rootp)->balance--) {
190 case 1: return False;
191 case 0: return True;
192 case -1: break;
193 default: tl_assert(0);
194 }
195 if ((*rootp)->child[0]->balance < 0) {
196 avl_swr( rootp );
197 (*rootp)->balance = 0;
198 (*rootp)->child[1]->balance = 0;
199 } else {
200 avl_swl( &((*rootp)->child[0]) );
201 avl_swr( rootp );
202 avl_nasty( *rootp );
203 }
204 } else {
205 (*rootp)->child[0] = left_subtree;
206 }
207 return False;
208 } else {
209 (*rootp)->child[0] = a;
210 if ((*rootp)->balance--)
211 return False;
212 return True;
213 }
214 tl_assert(0);/*NOTREACHED*/
215 }
216 else
217 if (cmpres < 0) {
218 /* insert into the right subtree */
219 if ((*rootp)->child[1]) {
220 AvlNode* right_subtree = (*rootp)->child[1];
221 if (avl_insert_wrk(&right_subtree, oldV, a, kCmp)) {
222 switch((*rootp)->balance++){
223 case -1: return False;
224 case 0: return True;
225 case 1: break;
226 default: tl_assert(0);
227 }
228 if ((*rootp)->child[1]->balance > 0) {
229 avl_swl( rootp );
230 (*rootp)->balance = 0;
231 (*rootp)->child[0]->balance = 0;
232 } else {
233 avl_swr( &((*rootp)->child[1]) );
234 avl_swl( rootp );
235 avl_nasty( *rootp );
236 }
237 } else {
238 (*rootp)->child[1] = right_subtree;
239 }
240 return False;
241 } else {
242 (*rootp)->child[1] = a;
243 if ((*rootp)->balance++)
244 return False;
245 return True;
246 }
247 tl_assert(0);/*NOTREACHED*/
248 }
249 else {
250 /* cmpres == 0, a duplicate - replace the val, but don't
251 incorporate the node in the tree */
252 oldV->b = True;
253 oldV->w = (*rootp)->val;
254 (*rootp)->val = a->val;
255 return False;
256 }
257 }
258
259 /* Remove an element a from the AVL tree t. a must be part of
260 the tree. Returns True if the depth of the tree has shrunk.
261 */
262 static
avl_remove_wrk(AvlNode ** rootp,AvlNode * a,Word (* kCmp)(UWord,UWord))263 Bool avl_remove_wrk ( AvlNode** rootp,
264 AvlNode* a,
265 Word(*kCmp)(UWord,UWord) )
266 {
267 Bool ch;
268 Word cmpres;
269 cmpres = kCmp ? /*boxed*/ kCmp( (*rootp)->key, a->key )
270 : /*unboxed*/ cmp_unsigned_Words( (UWord)(*rootp)->key,
271 (UWord)a->key );
272
273 if (cmpres > 0){
274 /* remove from the left subtree */
275 AvlNode* left_subtree = (*rootp)->child[0];
276 tl_assert(left_subtree);
277 ch = avl_remove_wrk(&left_subtree, a, kCmp);
278 (*rootp)->child[0]=left_subtree;
279 if (ch) {
280 switch ((*rootp)->balance++) {
281 case -1: return True;
282 case 0: return False;
283 case 1: break;
284 default: tl_assert(0);
285 }
286 switch ((*rootp)->child[1]->balance) {
287 case 0:
288 avl_swl( rootp );
289 (*rootp)->balance = -1;
290 (*rootp)->child[0]->balance = 1;
291 return False;
292 case 1:
293 avl_swl( rootp );
294 (*rootp)->balance = 0;
295 (*rootp)->child[0]->balance = 0;
296 return True;
297 case -1:
298 break;
299 default:
300 tl_assert(0);
301 }
302 avl_swr( &((*rootp)->child[1]) );
303 avl_swl( rootp );
304 avl_nasty( *rootp );
305 return True;
306 }
307 }
308 else
309 if (cmpres < 0) {
310 /* remove from the right subtree */
311 AvlNode* right_subtree = (*rootp)->child[1];
312 tl_assert(right_subtree);
313 ch = avl_remove_wrk(&right_subtree, a, kCmp);
314 (*rootp)->child[1] = right_subtree;
315 if (ch) {
316 switch ((*rootp)->balance--) {
317 case 1: return True;
318 case 0: return False;
319 case -1: break;
320 default: tl_assert(0);
321 }
322 switch ((*rootp)->child[0]->balance) {
323 case 0:
324 avl_swr( rootp );
325 (*rootp)->balance = 1;
326 (*rootp)->child[1]->balance = -1;
327 return False;
328 case -1:
329 avl_swr( rootp );
330 (*rootp)->balance = 0;
331 (*rootp)->child[1]->balance = 0;
332 return True;
333 case 1:
334 break;
335 default:
336 tl_assert(0);
337 }
338 avl_swl( &((*rootp)->child[0]) );
339 avl_swr( rootp );
340 avl_nasty( *rootp );
341 return True;
342 }
343 }
344 else {
345 tl_assert(cmpres == 0);
346 tl_assert((*rootp)==a);
347 return avl_removeroot_wrk(rootp, kCmp);
348 }
349 return 0;
350 }
351
352 /* Remove the root of the AVL tree *rootp.
353 * Warning: dumps core if *rootp is empty
354 */
355 static
avl_removeroot_wrk(AvlNode ** rootp,Word (* kCmp)(UWord,UWord))356 Bool avl_removeroot_wrk ( AvlNode** rootp,
357 Word(*kCmp)(UWord,UWord) )
358 {
359 Bool ch;
360 AvlNode* a;
361 if (!(*rootp)->child[0]) {
362 if (!(*rootp)->child[1]) {
363 (*rootp) = 0;
364 return True;
365 }
366 (*rootp) = (*rootp)->child[1];
367 return True;
368 }
369 if (!(*rootp)->child[1]) {
370 (*rootp) = (*rootp)->child[0];
371 return True;
372 }
373 if ((*rootp)->balance < 0) {
374 /* remove from the left subtree */
375 a = (*rootp)->child[0];
376 while (a->child[1]) a = a->child[1];
377 } else {
378 /* remove from the right subtree */
379 a = (*rootp)->child[1];
380 while (a->child[0]) a = a->child[0];
381 }
382 ch = avl_remove_wrk(rootp, a, kCmp);
383 a->child[0] = (*rootp)->child[0];
384 a->child[1] = (*rootp)->child[1];
385 a->balance = (*rootp)->balance;
386 (*rootp) = a;
387 if(a->balance == 0) return ch;
388 return False;
389 }
390
391 static
avl_find_node(AvlNode * t,Word k,Word (* kCmp)(UWord,UWord))392 AvlNode* avl_find_node ( AvlNode* t, Word k, Word(*kCmp)(UWord,UWord) )
393 {
394 if (kCmp) {
395 /* Boxed comparisons */
396 Word cmpresS;
397 while (True) {
398 if (t == NULL) return NULL;
399 cmpresS = kCmp(t->key, k);
400 if (cmpresS > 0) t = t->child[0]; else
401 if (cmpresS < 0) t = t->child[1]; else
402 return t;
403 }
404 } else {
405 /* Unboxed comparisons */
406 Word cmpresS; /* signed */
407 UWord cmpresU; /* unsigned */
408 while (True) {
409 if (t == NULL) return NULL; /* unlikely ==> predictable */
410 cmpresS = cmp_unsigned_Words( (UWord)t->key, (UWord)k );
411 if (cmpresS == 0) return t; /* unlikely ==> predictable */
412 cmpresU = (UWord)cmpresS;
413 cmpresU >>=/*unsigned*/ (8 * sizeof(cmpresU) - 1);
414 t = t->child[cmpresU];
415 }
416 }
417 }
418
419 static
avl_find_bounds(AvlNode * t,UWord * kMinP,UWord * vMinP,UWord * kMaxP,UWord * vMaxP,UWord minKey,UWord minVal,UWord maxKey,UWord maxVal,UWord key,Word (* kCmp)(UWord,UWord))420 Bool avl_find_bounds ( AvlNode* t,
421 /*OUT*/UWord* kMinP, /*OUT*/UWord* vMinP,
422 /*OUT*/UWord* kMaxP, /*OUT*/UWord* vMaxP,
423 UWord minKey, UWord minVal,
424 UWord maxKey, UWord maxVal,
425 UWord key,
426 Word(*kCmp)(UWord,UWord) )
427 {
428 UWord kLowerBound = minKey;
429 UWord vLowerBound = minVal;
430 UWord kUpperBound = maxKey;
431 UWord vUpperBound = maxVal;
432 while (t) {
433 Word cmpresS = kCmp ? kCmp(t->key, key)
434 : cmp_unsigned_Words(t->key, key);
435 if (cmpresS < 0) {
436 kLowerBound = t->key;
437 vLowerBound = t->val;
438 t = t->child[1];
439 continue;
440 }
441 if (cmpresS > 0) {
442 kUpperBound = t->key;
443 vUpperBound = t->val;
444 t = t->child[0];
445 continue;
446 }
447 /* We should never get here. If we do, it means the given key
448 is actually present in the tree, which means the original
449 call was invalid -- an error on the caller's part, and we
450 cannot give any meaningful values for the bounds. (Well,
451 maybe we could, but we're not gonna. Ner!) */
452 return False;
453 }
454 if (kMinP) *kMinP = kLowerBound;
455 if (vMinP) *vMinP = vLowerBound;
456 if (kMaxP) *kMaxP = kUpperBound;
457 if (vMaxP) *vMaxP = vUpperBound;
458 return True;
459 }
460
461 // Clear the iterator stack.
stackClear(WordFM * fm)462 static void stackClear(WordFM* fm)
463 {
464 Int i;
465 tl_assert(fm);
466 for (i = 0; i < WFM_STKMAX; i++) {
467 fm->nodeStack[i] = NULL;
468 fm->numStack[i] = 0;
469 }
470 fm->stackTop = 0;
471 }
472
473 // Push onto the iterator stack.
stackPush(WordFM * fm,AvlNode * n,Int i)474 static inline void stackPush(WordFM* fm, AvlNode* n, Int i)
475 {
476 tl_assert(fm->stackTop < WFM_STKMAX);
477 tl_assert(1 <= i && i <= 3);
478 fm->nodeStack[fm->stackTop] = n;
479 fm-> numStack[fm->stackTop] = i;
480 fm->stackTop++;
481 }
482
483 // Pop from the iterator stack.
stackPop(WordFM * fm,AvlNode ** n,Int * i)484 static inline Bool stackPop(WordFM* fm, AvlNode** n, Int* i)
485 {
486 tl_assert(fm->stackTop <= WFM_STKMAX);
487
488 if (fm->stackTop > 0) {
489 fm->stackTop--;
490 *n = fm->nodeStack[fm->stackTop];
491 *i = fm-> numStack[fm->stackTop];
492 tl_assert(1 <= *i && *i <= 3);
493 fm->nodeStack[fm->stackTop] = NULL;
494 fm-> numStack[fm->stackTop] = 0;
495 return True;
496 } else {
497 return False;
498 }
499 }
500
501 static
avl_dopy(AvlNode * nd,UWord (* dopyK)(UWord),UWord (* dopyV)(UWord),void * (alloc_nofail)(const HChar *,SizeT),const HChar * cc)502 AvlNode* avl_dopy ( AvlNode* nd,
503 UWord(*dopyK)(UWord),
504 UWord(*dopyV)(UWord),
505 void*(alloc_nofail)(const HChar*,SizeT),
506 const HChar* cc )
507 {
508 AvlNode* nyu;
509 if (! nd)
510 return NULL;
511 nyu = alloc_nofail(cc, sizeof(AvlNode));
512 tl_assert(nyu);
513
514 nyu->child[0] = nd->child[0];
515 nyu->child[1] = nd->child[1];
516 nyu->balance = nd->balance;
517
518 /* Copy key */
519 if (dopyK) {
520 nyu->key = dopyK( nd->key );
521 if (nd->key != 0 && nyu->key == 0)
522 return NULL; /* oom in key dcopy */
523 } else {
524 /* copying assumedly unboxed keys */
525 nyu->key = nd->key;
526 }
527
528 /* Copy val */
529 if (dopyV) {
530 nyu->val = dopyV( nd->val );
531 if (nd->val != 0 && nyu->val == 0)
532 return NULL; /* oom in val dcopy */
533 } else {
534 /* copying assumedly unboxed vals */
535 nyu->val = nd->val;
536 }
537
538 /* Copy subtrees */
539 if (nyu->child[0]) {
540 nyu->child[0] = avl_dopy( nyu->child[0], dopyK, dopyV,
541 alloc_nofail, cc );
542 if (! nyu->child[0])
543 return NULL;
544 }
545 if (nyu->child[1]) {
546 nyu->child[1] = avl_dopy( nyu->child[1], dopyK, dopyV,
547 alloc_nofail, cc );
548 if (! nyu->child[1])
549 return NULL;
550 }
551
552 return nyu;
553 }
554
555 /* Initialise a WordFM. */
initFM(WordFM * fm,void * (* alloc_nofail)(const HChar *,SizeT),const HChar * cc,void (* dealloc)(void *),Word (* kCmp)(UWord,UWord))556 static void initFM ( WordFM* fm,
557 void* (*alloc_nofail)( const HChar*, SizeT ),
558 const HChar* cc,
559 void (*dealloc)(void*),
560 Word (*kCmp)(UWord,UWord) )
561 {
562 fm->root = 0;
563 fm->kCmp = kCmp;
564 fm->alloc_nofail = alloc_nofail;
565 fm->cc = cc;
566 fm->dealloc = dealloc;
567 fm->stackTop = 0;
568 }
569
570 /* --- Public interface functions --- */
571
572 /* Allocate and initialise a WordFM. If kCmp is non-NULL, elements in
573 the set are ordered according to the ordering specified by kCmp,
574 which becomes obvious if you use VG_(initIterFM),
575 VG_(initIterAtFM), VG_(nextIterFM), VG_(doneIterFM) to iterate over
576 sections of the map, or the whole thing. If kCmp is NULL then the
577 ordering used is unsigned word ordering (UWord) on the key
578 values. */
VG_(newFM)579 WordFM* VG_(newFM) ( void* (*alloc_nofail)( const HChar*, SizeT ),
580 const HChar* cc,
581 void (*dealloc)(void*),
582 Word (*kCmp)(UWord,UWord) )
583 {
584 WordFM* fm = alloc_nofail(cc, sizeof(WordFM));
585 tl_assert(fm);
586 initFM(fm, alloc_nofail, cc, dealloc, kCmp);
587 return fm;
588 }
589
avl_free(AvlNode * nd,void (* kFin)(UWord),void (* vFin)(UWord),void (* dealloc)(void *))590 static void avl_free ( AvlNode* nd,
591 void(*kFin)(UWord),
592 void(*vFin)(UWord),
593 void(*dealloc)(void*) )
594 {
595 if (!nd)
596 return;
597 if (nd->child[0])
598 avl_free(nd->child[0], kFin, vFin, dealloc);
599 if (nd->child[1])
600 avl_free(nd->child[1], kFin, vFin, dealloc);
601 if (kFin)
602 kFin( nd->key );
603 if (vFin)
604 vFin( nd->val );
605 VG_(memset)(nd, 0, sizeof(AvlNode));
606 dealloc(nd);
607 }
608
609 /* Free up the FM. If kFin is non-NULL, it is applied to keys
610 before the FM is deleted; ditto with vFin for vals. */
VG_(deleteFM)611 void VG_(deleteFM) ( WordFM* fm, void(*kFin)(UWord), void(*vFin)(UWord) )
612 {
613 void(*dealloc)(void*) = fm->dealloc;
614 avl_free( fm->root, kFin, vFin, dealloc );
615 VG_(memset)(fm, 0, sizeof(WordFM) );
616 dealloc(fm);
617 }
618
619 /* Add (k,v) to fm. */
VG_(addToFM)620 Bool VG_(addToFM) ( WordFM* fm, UWord k, UWord v )
621 {
622 MaybeWord oldV;
623 AvlNode* node;
624 node = fm->alloc_nofail( fm->cc, sizeof(AvlNode) );
625 node->key = k;
626 node->val = v;
627 oldV.b = False;
628 oldV.w = 0;
629 avl_insert_wrk( &fm->root, &oldV, node, fm->kCmp );
630 //if (oldV.b && fm->vFin)
631 // fm->vFin( oldV.w );
632 if (oldV.b)
633 fm->dealloc(node);
634 return oldV.b;
635 }
636
637 // Delete key from fm, returning associated key and val if found
VG_(delFromFM)638 Bool VG_(delFromFM) ( WordFM* fm,
639 /*OUT*/UWord* oldK, /*OUT*/UWord* oldV, UWord key )
640 {
641 AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
642 if (node) {
643 avl_remove_wrk( &fm->root, node, fm->kCmp );
644 if (oldK)
645 *oldK = node->key;
646 if (oldV)
647 *oldV = node->val;
648 fm->dealloc(node);
649 return True;
650 } else {
651 return False;
652 }
653 }
654
655 // Look up in fm, assigning found key & val at spec'd addresses
VG_(lookupFM)656 Bool VG_(lookupFM) ( WordFM* fm,
657 /*OUT*/UWord* keyP, /*OUT*/UWord* valP, UWord key )
658 {
659 AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
660 if (node) {
661 if (keyP)
662 *keyP = node->key;
663 if (valP)
664 *valP = node->val;
665 return True;
666 } else {
667 return False;
668 }
669 }
670
671 // See comment in pub_tool_wordfm.h for explanation
VG_(findBoundsFM)672 Bool VG_(findBoundsFM)( WordFM* fm,
673 /*OUT*/UWord* kMinP, /*OUT*/UWord* vMinP,
674 /*OUT*/UWord* kMaxP, /*OUT*/UWord* vMaxP,
675 UWord minKey, UWord minVal,
676 UWord maxKey, UWord maxVal,
677 UWord key )
678 {
679 /* really we should assert that minKey <= key <= maxKey,
680 where <= is as defined by fm->kCmp. */
681 return avl_find_bounds( fm->root, kMinP, vMinP,
682 kMaxP, vMaxP,
683 minKey, minVal,
684 maxKey, maxVal,
685 key, fm->kCmp );
686 }
687
688 // See comment in pub_tool_wordfm.h for performance warning
VG_(sizeFM)689 UWord VG_(sizeFM) ( WordFM* fm )
690 {
691 // Hmm, this is a bad way to do this
692 return fm->root ? size_avl_nonNull( fm->root ) : 0;
693 }
694
695 // NB UNTESTED! TEST BEFORE USE!
696 //Bool VG_(isEmptyFM)( WordFM* fm )
697 //{
698 // return fm->root ? False : True;
699 //}
700
701 // set up FM for iteration
VG_(initIterFM)702 void VG_(initIterFM) ( WordFM* fm )
703 {
704 tl_assert(fm);
705 stackClear(fm);
706 if (fm->root)
707 stackPush(fm, fm->root, 1);
708 }
709
710 // set up FM for iteration so that the first key subsequently produced
711 // by VG_(nextIterFM) is the smallest key in the map >= start_at.
712 // Naturally ">=" is defined by the comparison function supplied to
713 // VG_(newFM), as documented above.
VG_(initIterAtFM)714 void VG_(initIterAtFM) ( WordFM* fm, UWord start_at )
715 {
716 Int i;
717 AvlNode *n, *t;
718 Word cmpresS; /* signed */
719 UWord cmpresU; /* unsigned */
720
721 tl_assert(fm);
722 stackClear(fm);
723
724 if (!fm->root)
725 return;
726
727 n = NULL;
728 // We need to do regular search and fill in the stack.
729 t = fm->root;
730
731 while (True) {
732 if (t == NULL) return;
733
734 cmpresS
735 = fm->kCmp ? /*boxed*/ fm->kCmp( t->key, start_at )
736 : /*unboxed*/ cmp_unsigned_Words( t->key, start_at );
737
738 if (cmpresS == 0) {
739 // We found the exact key -- we are done.
740 // The iteration should start with this node.
741 stackPush(fm, t, 2);
742 // The stack now looks like {2, 2, ... ,2, 2}
743 return;
744 }
745 cmpresU = (UWord)cmpresS;
746 cmpresU >>=/*unsigned*/ (8 * sizeof(cmpresU) - 1);
747 if (!cmpresU) {
748 // Push this node only if we go to the left child.
749 stackPush(fm, t, 2);
750 }
751 t = t->child[cmpresU];
752 }
753 if (stackPop(fm, &n, &i)) {
754 // If we've pushed something to stack and did not find the exact key,
755 // we must fix the top element of stack.
756 tl_assert(i == 2);
757 stackPush(fm, n, 3);
758 // the stack looks like {2, 2, ..., 2, 3}
759 }
760 }
761
762 // get next key/val pair. Will tl_assert if fm has been modified
763 // or looked up in since initIter{,At}FM was called.
VG_(nextIterFM)764 Bool VG_(nextIterFM) ( WordFM* fm, /*OUT*/UWord* pKey, /*OUT*/UWord* pVal )
765 {
766 Int i = 0;
767 AvlNode* n = NULL;
768
769 tl_assert(fm);
770
771 // This in-order traversal requires each node to be pushed and popped
772 // three times. These could be avoided by updating nodes in-situ on the
773 // top of the stack, but the push/pop cost is so small that it's worth
774 // keeping this loop in this simpler form.
775 while (stackPop(fm, &n, &i)) {
776 switch (i) {
777 case 1: case_1:
778 stackPush(fm, n, 2);
779 /* if (n->child[0]) stackPush(fm, n->child[0], 1); */
780 if (n->child[0]) { n = n->child[0]; goto case_1; }
781 break;
782 case 2:
783 stackPush(fm, n, 3);
784 if (pKey) *pKey = n->key;
785 if (pVal) *pVal = n->val;
786 return True;
787 case 3:
788 /* if (n->child[1]) stackPush(fm, n->child[1], 1); */
789 if (n->child[1]) { n = n->child[1]; goto case_1; }
790 break;
791 default:
792 tl_assert(0);
793 }
794 }
795
796 // Stack empty, iterator is exhausted, return NULL
797 return False;
798 }
799
800 // clear the I'm iterating flag
VG_(doneIterFM)801 void VG_(doneIterFM) ( WordFM* fm )
802 {
803 }
804
VG_(dopyFM)805 WordFM* VG_(dopyFM) ( WordFM* fm, UWord(*dopyK)(UWord), UWord(*dopyV)(UWord) )
806 {
807 WordFM* nyu;
808
809 /* can't clone the fm whilst iterating on it */
810 tl_assert(fm->stackTop == 0);
811
812 nyu = fm->alloc_nofail( fm->cc, sizeof(WordFM) );
813 tl_assert(nyu);
814
815 *nyu = *fm;
816
817 fm->stackTop = 0;
818 VG_(memset)(fm->nodeStack, 0, sizeof(fm->nodeStack));
819 VG_(memset)(fm->numStack, 0, sizeof(fm->numStack));
820
821 if (nyu->root) {
822 nyu->root = avl_dopy( nyu->root, dopyK, dopyV,
823 fm->alloc_nofail, fm->cc );
824 if (! nyu->root)
825 return NULL;
826 }
827
828 return nyu;
829 }
830
831 // admin: what's the 'common' allocation size (for tree nodes?)
VG_(getNodeSizeFM)832 SizeT VG_(getNodeSizeFM)( void )
833 {
834 return sizeof(AvlNode);
835 }
836
837 //------------------------------------------------------------------//
838 //--- end WordFM ---//
839 //--- Implementation ---//
840 //------------------------------------------------------------------//
841
842 //------------------------------------------------------------------//
843 //--- WordBag (unboxed words only) ---//
844 //--- Implementation ---//
845 //------------------------------------------------------------------//
846
847 /* A trivial container, to make it opaque. */
848 struct _WordBag {
849 WordFM* fm;
850 };
851
VG_(newBag)852 WordBag* VG_(newBag) ( void* (*alloc_nofail)( const HChar*, SizeT ),
853 const HChar* cc,
854 void (*dealloc)(void*) )
855 {
856 WordBag* bag = alloc_nofail(cc, sizeof(WordBag));
857 bag->fm = VG_(newFM)( alloc_nofail, cc, dealloc, NULL );
858 return bag;
859 }
860
VG_(deleteBag)861 void VG_(deleteBag) ( WordBag* bag )
862 {
863 void (*dealloc)(void*) = bag->fm->dealloc;
864 VG_(deleteFM)( bag->fm, NULL, NULL );
865 VG_(memset)(bag, 0, sizeof(WordBag));
866 dealloc(bag);
867 }
868
VG_(addToBag)869 void VG_(addToBag)( WordBag* bag, UWord w )
870 {
871 UWord key, count;
872 if (VG_(lookupFM)(bag->fm, &key, &count, w)) {
873 tl_assert(key == w);
874 tl_assert(count >= 1);
875 VG_(addToFM)(bag->fm, w, count+1);
876 } else {
877 VG_(addToFM)(bag->fm, w, 1);
878 }
879 }
880
VG_(elemBag)881 UWord VG_(elemBag) ( WordBag* bag, UWord w )
882 {
883 UWord key, count;
884 if (VG_(lookupFM)( bag->fm, &key, &count, w)) {
885 tl_assert(key == w);
886 tl_assert(count >= 1);
887 return count;
888 } else {
889 return 0;
890 }
891 }
892
VG_(sizeUniqueBag)893 UWord VG_(sizeUniqueBag) ( WordBag* bag )
894 {
895 return VG_(sizeFM)( bag->fm );
896 }
897
sizeTotalBag_wrk(AvlNode * nd)898 static UWord sizeTotalBag_wrk ( AvlNode* nd )
899 {
900 /* unchecked pre: nd is non-NULL */
901 UWord w = nd->val;
902 tl_assert(w >= 1);
903 if (nd->child[0])
904 w += sizeTotalBag_wrk(nd->child[0]);
905 if (nd->child[1])
906 w += sizeTotalBag_wrk(nd->child[1]);
907 return w;
908 }
VG_(sizeTotalBag)909 UWord VG_(sizeTotalBag)( WordBag* bag )
910 {
911 if (bag->fm->root)
912 return sizeTotalBag_wrk(bag->fm->root);
913 else
914 return 0;
915 }
916
VG_(delFromBag)917 Bool VG_(delFromBag)( WordBag* bag, UWord w )
918 {
919 UWord key, count;
920 if (VG_(lookupFM)(bag->fm, &key, &count, w)) {
921 tl_assert(key == w);
922 tl_assert(count >= 1);
923 if (count > 1) {
924 VG_(addToFM)(bag->fm, w, count-1);
925 } else {
926 tl_assert(count == 1);
927 VG_(delFromFM)( bag->fm, NULL, NULL, w );
928 }
929 return True;
930 } else {
931 return False;
932 }
933 }
934
VG_(isEmptyBag)935 Bool VG_(isEmptyBag)( WordBag* bag )
936 {
937 return VG_(sizeFM)(bag->fm) == 0;
938 }
939
VG_(isSingletonTotalBag)940 Bool VG_(isSingletonTotalBag)( WordBag* bag )
941 {
942 AvlNode* nd;
943 if (VG_(sizeFM)(bag->fm) != 1)
944 return False;
945 nd = bag->fm->root;
946 tl_assert(nd);
947 tl_assert(!nd->child[0]);
948 tl_assert(!nd->child[1]);
949 return nd->val == 1;
950 }
951
VG_(anyElementOfBag)952 UWord VG_(anyElementOfBag)( WordBag* bag )
953 {
954 /* Return an arbitrarily chosen element in the bag. We might as
955 well return the one at the root of the underlying AVL tree. */
956 AvlNode* nd = bag->fm->root;
957 tl_assert(nd); /* if this fails, 'bag' is empty - caller is in error. */
958 tl_assert(nd->val >= 1);
959 return nd->key;
960 }
961
VG_(initIterBag)962 void VG_(initIterBag)( WordBag* bag )
963 {
964 VG_(initIterFM)(bag->fm);
965 }
966
VG_(nextIterBag)967 Bool VG_(nextIterBag)( WordBag* bag, /*OUT*/UWord* pVal, /*OUT*/UWord* pCount )
968 {
969 return VG_(nextIterFM)( bag->fm, pVal, pCount );
970 }
971
VG_(doneIterBag)972 void VG_(doneIterBag)( WordBag* bag )
973 {
974 VG_(doneIterFM)( bag->fm );
975 }
976
977 //------------------------------------------------------------------//
978 //--- end WordBag (unboxed words only) ---//
979 //--- Implementation ---//
980 //------------------------------------------------------------------//
981
982 /*--------------------------------------------------------------------*/
983 /*--- end m_wordfm.c ---*/
984 /*--------------------------------------------------------------------*/
985