blob: 6126ff0fbbca93148a6eeb82aece275e5ce07eaf [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
sewardj4d474d02008-02-11 11:34:59 +000012 Copyright (C) 2007-2008 Julian Seward
sewardjb4112022007-11-09 22:49:28 +000013 jseward@acm.org
14
15 This code is based on previous work by Nicholas Nethercote
16 (coregrind/m_oset.c) which is
17
sewardj4d474d02008-02-11 11:34:59 +000018 Copyright (C) 2005-2008 Nicholas Nethercote
sewardjb4112022007-11-09 22:49:28 +000019 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
sewardjae5137e2008-01-17 23:19:54 +000056
57#ifdef HG_WORDFM_STANDALONE // standalone compilation
58// Standalone mode (for testing).
59// On x86_64 compile like this:
60// gcc -m64 hg_wordfm.c -I../include -I../VEX/pub
61// -DVGA_amd64=1 -DHG_WORDFM_STANDALONE -g -O -Wall
62# include <assert.h>
63# include <string.h>
64# include <stdio.h>
65# include <stdlib.h>
66
67# undef tl_assert
68# define tl_assert assert
69# define vgPlain_memset memset
70
71#endif /* def HG_WORDFM_STANDALONE */
72
73
sewardjb4112022007-11-09 22:49:28 +000074#define HG_(str) VGAPPEND(vgHelgrind_,str)
75#include "hg_wordfm.h"
76
77//------------------------------------------------------------------//
78//--- WordFM ---//
79//--- Implementation ---//
80//------------------------------------------------------------------//
81
82/* One element of the AVL tree */
83typedef
84 struct _AvlNode {
sewardj250ec2e2008-02-15 22:02:30 +000085 UWord key;
86 UWord val;
sewardjb4112022007-11-09 22:49:28 +000087 struct _AvlNode* child[2]; /* [0] is left subtree, [1] is right */
88 Char balance; /* do not make this unsigned */
89 }
90 AvlNode;
91
92typedef
93 struct {
sewardj250ec2e2008-02-15 22:02:30 +000094 UWord w;
sewardjb4112022007-11-09 22:49:28 +000095 Bool b;
96 }
97 MaybeWord;
98
99#define WFM_STKMAX 32 // At most 2**32 entries can be iterated over
100
101struct _WordFM {
102 AvlNode* root;
103 void* (*alloc_nofail)( SizeT );
104 void (*dealloc)(void*);
sewardj250ec2e2008-02-15 22:02:30 +0000105 Word (*kCmp)(UWord,UWord);
sewardjb4112022007-11-09 22:49:28 +0000106 AvlNode* nodeStack[WFM_STKMAX]; // Iterator node stack
107 Int numStack[WFM_STKMAX]; // Iterator num stack
108 Int stackTop; // Iterator stack pointer, one past end
109};
110
111/* forward */
sewardj250ec2e2008-02-15 22:02:30 +0000112static Bool avl_removeroot_wrk(AvlNode** t, Word(*kCmp)(UWord,UWord));
sewardjb4112022007-11-09 22:49:28 +0000113
114/* Swing to the left. Warning: no balance maintainance. */
115static void avl_swl ( AvlNode** root )
116{
117 AvlNode* a = *root;
118 AvlNode* b = a->child[1];
119 *root = b;
120 a->child[1] = b->child[0];
121 b->child[0] = a;
122}
123
124/* Swing to the right. Warning: no balance maintainance. */
125static void avl_swr ( AvlNode** root )
126{
127 AvlNode* a = *root;
128 AvlNode* b = a->child[0];
129 *root = b;
130 a->child[0] = b->child[1];
131 b->child[1] = a;
132}
133
134/* Balance maintainance after especially nasty swings. */
135static void avl_nasty ( AvlNode* root )
136{
137 switch (root->balance) {
138 case -1:
139 root->child[0]->balance = 0;
140 root->child[1]->balance = 1;
141 break;
142 case 1:
143 root->child[0]->balance = -1;
144 root->child[1]->balance = 0;
145 break;
146 case 0:
147 root->child[0]->balance = 0;
148 root->child[1]->balance = 0;
149 break;
150 default:
151 tl_assert(0);
152 }
153 root->balance=0;
154}
155
156/* Find size of a non-NULL tree. */
sewardj250ec2e2008-02-15 22:02:30 +0000157static UWord size_avl_nonNull ( AvlNode* nd )
sewardjb4112022007-11-09 22:49:28 +0000158{
159 return 1 + (nd->child[0] ? size_avl_nonNull(nd->child[0]) : 0)
160 + (nd->child[1] ? size_avl_nonNull(nd->child[1]) : 0);
161}
162
sewardj250ec2e2008-02-15 22:02:30 +0000163/* Unsignedly compare w1 and w2. If w1 < w2, produce a negative
164 number; if w1 > w2 produce a positive number, and if w1 == w2
165 produce zero. */
166static inline Word cmp_unsigned_Words ( UWord w1, UWord w2 ) {
sewardj95e79002007-12-09 02:14:35 +0000167 if (w1 < w2) return -1;
168 if (w1 > w2) return 1;
169 return 0;
170}
171
sewardjb4112022007-11-09 22:49:28 +0000172/* Insert element a into the AVL tree t. Returns True if the depth of
173 the tree has grown. If element with that key is already present,
174 just copy a->val to existing node, first returning old ->val field
175 of existing node in *oldV, so that the caller can finalize it
176 however it wants.
177*/
178static
179Bool avl_insert_wrk ( AvlNode** rootp,
180 /*OUT*/MaybeWord* oldV,
181 AvlNode* a,
sewardj250ec2e2008-02-15 22:02:30 +0000182 Word (*kCmp)(UWord,UWord) )
sewardjb4112022007-11-09 22:49:28 +0000183{
184 Word cmpres;
185
186 /* initialize */
187 a->child[0] = 0;
188 a->child[1] = 0;
189 a->balance = 0;
190 oldV->b = False;
191
192 /* insert into an empty tree? */
193 if (!(*rootp)) {
194 (*rootp) = a;
195 return True;
196 }
197
198 cmpres = kCmp ? /*boxed*/ kCmp( (*rootp)->key, a->key )
sewardj250ec2e2008-02-15 22:02:30 +0000199 : /*unboxed*/ cmp_unsigned_Words( (UWord)(*rootp)->key,
200 (UWord)a->key );
sewardjb4112022007-11-09 22:49:28 +0000201
202 if (cmpres > 0) {
203 /* insert into the left subtree */
204 if ((*rootp)->child[0]) {
205 AvlNode* left_subtree = (*rootp)->child[0];
206 if (avl_insert_wrk(&left_subtree, oldV, a, kCmp)) {
207 switch ((*rootp)->balance--) {
208 case 1: return False;
209 case 0: return True;
210 case -1: break;
211 default: tl_assert(0);
212 }
213 if ((*rootp)->child[0]->balance < 0) {
214 avl_swr( rootp );
215 (*rootp)->balance = 0;
216 (*rootp)->child[1]->balance = 0;
217 } else {
218 avl_swl( &((*rootp)->child[0]) );
219 avl_swr( rootp );
220 avl_nasty( *rootp );
221 }
222 } else {
223 (*rootp)->child[0] = left_subtree;
224 }
225 return False;
226 } else {
227 (*rootp)->child[0] = a;
228 if ((*rootp)->balance--)
229 return False;
230 return True;
231 }
232 tl_assert(0);/*NOTREACHED*/
233 }
234 else
235 if (cmpres < 0) {
236 /* insert into the right subtree */
237 if ((*rootp)->child[1]) {
238 AvlNode* right_subtree = (*rootp)->child[1];
239 if (avl_insert_wrk(&right_subtree, oldV, a, kCmp)) {
240 switch((*rootp)->balance++){
241 case -1: return False;
242 case 0: return True;
243 case 1: break;
244 default: tl_assert(0);
245 }
246 if ((*rootp)->child[1]->balance > 0) {
247 avl_swl( rootp );
248 (*rootp)->balance = 0;
249 (*rootp)->child[0]->balance = 0;
250 } else {
251 avl_swr( &((*rootp)->child[1]) );
252 avl_swl( rootp );
253 avl_nasty( *rootp );
254 }
255 } else {
256 (*rootp)->child[1] = right_subtree;
257 }
258 return False;
259 } else {
260 (*rootp)->child[1] = a;
261 if ((*rootp)->balance++)
262 return False;
263 return True;
264 }
265 tl_assert(0);/*NOTREACHED*/
266 }
267 else {
268 /* cmpres == 0, a duplicate - replace the val, but don't
269 incorporate the node in the tree */
270 oldV->b = True;
271 oldV->w = (*rootp)->val;
272 (*rootp)->val = a->val;
273 return False;
274 }
275}
276
277/* Remove an element a from the AVL tree t. a must be part of
278 the tree. Returns True if the depth of the tree has shrunk.
279*/
280static
281Bool avl_remove_wrk ( AvlNode** rootp,
282 AvlNode* a,
sewardj250ec2e2008-02-15 22:02:30 +0000283 Word(*kCmp)(UWord,UWord) )
sewardjb4112022007-11-09 22:49:28 +0000284{
285 Bool ch;
286 Word cmpres;
287 cmpres = kCmp ? /*boxed*/ kCmp( (*rootp)->key, a->key )
sewardj250ec2e2008-02-15 22:02:30 +0000288 : /*unboxed*/ cmp_unsigned_Words( (UWord)(*rootp)->key,
289 (UWord)a->key );
sewardjb4112022007-11-09 22:49:28 +0000290
291 if (cmpres > 0){
292 /* remove from the left subtree */
293 AvlNode* left_subtree = (*rootp)->child[0];
294 tl_assert(left_subtree);
295 ch = avl_remove_wrk(&left_subtree, a, kCmp);
296 (*rootp)->child[0]=left_subtree;
297 if (ch) {
298 switch ((*rootp)->balance++) {
299 case -1: return True;
300 case 0: return False;
301 case 1: break;
302 default: tl_assert(0);
303 }
304 switch ((*rootp)->child[1]->balance) {
305 case 0:
306 avl_swl( rootp );
307 (*rootp)->balance = -1;
308 (*rootp)->child[0]->balance = 1;
309 return False;
310 case 1:
311 avl_swl( rootp );
312 (*rootp)->balance = 0;
313 (*rootp)->child[0]->balance = 0;
314 return True;
315 case -1:
316 break;
317 default:
318 tl_assert(0);
319 }
320 avl_swr( &((*rootp)->child[1]) );
321 avl_swl( rootp );
322 avl_nasty( *rootp );
323 return True;
324 }
325 }
326 else
327 if (cmpres < 0) {
328 /* remove from the right subtree */
329 AvlNode* right_subtree = (*rootp)->child[1];
330 tl_assert(right_subtree);
331 ch = avl_remove_wrk(&right_subtree, a, kCmp);
332 (*rootp)->child[1] = right_subtree;
333 if (ch) {
334 switch ((*rootp)->balance--) {
335 case 1: return True;
336 case 0: return False;
337 case -1: break;
338 default: tl_assert(0);
339 }
340 switch ((*rootp)->child[0]->balance) {
341 case 0:
342 avl_swr( rootp );
343 (*rootp)->balance = 1;
344 (*rootp)->child[1]->balance = -1;
345 return False;
346 case -1:
347 avl_swr( rootp );
348 (*rootp)->balance = 0;
349 (*rootp)->child[1]->balance = 0;
350 return True;
351 case 1:
352 break;
353 default:
354 tl_assert(0);
355 }
356 avl_swl( &((*rootp)->child[0]) );
357 avl_swr( rootp );
358 avl_nasty( *rootp );
359 return True;
360 }
361 }
362 else {
363 tl_assert(cmpres == 0);
364 tl_assert((*rootp)==a);
365 return avl_removeroot_wrk(rootp, kCmp);
366 }
367 return 0;
368}
369
370/* Remove the root of the AVL tree *rootp.
371 * Warning: dumps core if *rootp is empty
372 */
373static
374Bool avl_removeroot_wrk ( AvlNode** rootp,
sewardj250ec2e2008-02-15 22:02:30 +0000375 Word(*kCmp)(UWord,UWord) )
sewardjb4112022007-11-09 22:49:28 +0000376{
377 Bool ch;
378 AvlNode* a;
379 if (!(*rootp)->child[0]) {
380 if (!(*rootp)->child[1]) {
381 (*rootp) = 0;
382 return True;
383 }
384 (*rootp) = (*rootp)->child[1];
385 return True;
386 }
387 if (!(*rootp)->child[1]) {
388 (*rootp) = (*rootp)->child[0];
389 return True;
390 }
391 if ((*rootp)->balance < 0) {
392 /* remove from the left subtree */
393 a = (*rootp)->child[0];
394 while (a->child[1]) a = a->child[1];
395 } else {
396 /* remove from the right subtree */
397 a = (*rootp)->child[1];
398 while (a->child[0]) a = a->child[0];
399 }
400 ch = avl_remove_wrk(rootp, a, kCmp);
401 a->child[0] = (*rootp)->child[0];
402 a->child[1] = (*rootp)->child[1];
403 a->balance = (*rootp)->balance;
404 (*rootp) = a;
405 if(a->balance == 0) return ch;
406 return False;
407}
408
409static
sewardj250ec2e2008-02-15 22:02:30 +0000410AvlNode* avl_find_node ( AvlNode* t, Word k, Word(*kCmp)(UWord,UWord) )
sewardjb4112022007-11-09 22:49:28 +0000411{
412 if (kCmp) {
413 /* Boxed comparisons */
sewardj95e79002007-12-09 02:14:35 +0000414 Word cmpresS;
sewardjb4112022007-11-09 22:49:28 +0000415 while (True) {
416 if (t == NULL) return NULL;
sewardj95e79002007-12-09 02:14:35 +0000417 cmpresS = kCmp(t->key, k);
418 if (cmpresS > 0) t = t->child[0]; else
419 if (cmpresS < 0) t = t->child[1]; else
sewardjb4112022007-11-09 22:49:28 +0000420 return t;
421 }
422 } else {
423 /* Unboxed comparisons */
sewardj95e79002007-12-09 02:14:35 +0000424 Word cmpresS; /* signed */
sewardjb4112022007-11-09 22:49:28 +0000425 UWord cmpresU; /* unsigned */
426 while (True) {
427 if (t == NULL) return NULL; /* unlikely ==> predictable */
sewardj250ec2e2008-02-15 22:02:30 +0000428 cmpresS = cmp_unsigned_Words( (UWord)t->key, (UWord)k );
sewardj95e79002007-12-09 02:14:35 +0000429 if (cmpresS == 0) return t; /* unlikely ==> predictable */
430 cmpresU = (UWord)cmpresS;
sewardjefd3b4d2007-12-02 02:05:23 +0000431 cmpresU >>=/*unsigned*/ (8 * sizeof(cmpresU) - 1);
sewardjb4112022007-11-09 22:49:28 +0000432 t = t->child[cmpresU];
433 }
434 }
435}
436
437// Clear the iterator stack.
438static void stackClear(WordFM* fm)
439{
440 Int i;
441 tl_assert(fm);
442 for (i = 0; i < WFM_STKMAX; i++) {
443 fm->nodeStack[i] = NULL;
444 fm->numStack[i] = 0;
445 }
446 fm->stackTop = 0;
447}
448
449// Push onto the iterator stack.
450static inline void stackPush(WordFM* fm, AvlNode* n, Int i)
451{
452 tl_assert(fm->stackTop < WFM_STKMAX);
453 tl_assert(1 <= i && i <= 3);
454 fm->nodeStack[fm->stackTop] = n;
455 fm-> numStack[fm->stackTop] = i;
456 fm->stackTop++;
457}
458
459// Pop from the iterator stack.
460static inline Bool stackPop(WordFM* fm, AvlNode** n, Int* i)
461{
462 tl_assert(fm->stackTop <= WFM_STKMAX);
463
464 if (fm->stackTop > 0) {
465 fm->stackTop--;
466 *n = fm->nodeStack[fm->stackTop];
467 *i = fm-> numStack[fm->stackTop];
468 tl_assert(1 <= *i && *i <= 3);
469 fm->nodeStack[fm->stackTop] = NULL;
470 fm-> numStack[fm->stackTop] = 0;
471 return True;
472 } else {
473 return False;
474 }
475}
476
477static
478AvlNode* avl_dopy ( AvlNode* nd,
sewardj250ec2e2008-02-15 22:02:30 +0000479 UWord(*dopyK)(UWord),
480 UWord(*dopyV)(UWord),
sewardjb4112022007-11-09 22:49:28 +0000481 void*(alloc_nofail)(SizeT) )
482{
483 AvlNode* nyu;
484 if (! nd)
485 return NULL;
486 nyu = alloc_nofail(sizeof(AvlNode));
487 tl_assert(nyu);
488
489 nyu->child[0] = nd->child[0];
490 nyu->child[1] = nd->child[1];
491 nyu->balance = nd->balance;
492
493 /* Copy key */
494 if (dopyK) {
495 nyu->key = dopyK( nd->key );
496 if (nd->key != 0 && nyu->key == 0)
497 return NULL; /* oom in key dcopy */
498 } else {
499 /* copying assumedly unboxed keys */
500 nyu->key = nd->key;
501 }
502
503 /* Copy val */
504 if (dopyV) {
505 nyu->val = dopyV( nd->val );
506 if (nd->val != 0 && nyu->val == 0)
507 return NULL; /* oom in val dcopy */
508 } else {
509 /* copying assumedly unboxed vals */
510 nyu->val = nd->val;
511 }
512
513 /* Copy subtrees */
514 if (nyu->child[0]) {
515 nyu->child[0] = avl_dopy( nyu->child[0], dopyK, dopyV, alloc_nofail );
516 if (! nyu->child[0])
517 return NULL;
518 }
519 if (nyu->child[1]) {
520 nyu->child[1] = avl_dopy( nyu->child[1], dopyK, dopyV, alloc_nofail );
521 if (! nyu->child[1])
522 return NULL;
523 }
524
525 return nyu;
526}
527
528/* Initialise a WordFM. */
529static void initFM ( WordFM* fm,
530 void* (*alloc_nofail)( SizeT ),
531 void (*dealloc)(void*),
sewardj250ec2e2008-02-15 22:02:30 +0000532 Word (*kCmp)(UWord,UWord) )
sewardjb4112022007-11-09 22:49:28 +0000533{
534 fm->root = 0;
535 fm->kCmp = kCmp;
536 fm->alloc_nofail = alloc_nofail;
537 fm->dealloc = dealloc;
538 fm->stackTop = 0;
539}
540
541/* --- Public interface functions --- */
542
sewardj250ec2e2008-02-15 22:02:30 +0000543/* Allocate and initialise a WordFM. If kCmp is non-NULL, elements in
544 the set are ordered according to the ordering specified by kCmp,
545 which becomes obvious if you use VG_(initIterFM),
546 VG_(initIterAtFM), VG_(nextIterFM), VG_(doneIterFM) to iterate over
sewardjfc4b63a2008-02-17 11:46:58 +0000547 sections of the map, or the whole thing. If kCmp is NULL then the
548 ordering used is unsigned word ordering (UWord) on the key
549 values. */
sewardjb4112022007-11-09 22:49:28 +0000550WordFM* HG_(newFM) ( void* (*alloc_nofail)( SizeT ),
551 void (*dealloc)(void*),
sewardj250ec2e2008-02-15 22:02:30 +0000552 Word (*kCmp)(UWord,UWord) )
sewardjb4112022007-11-09 22:49:28 +0000553{
554 WordFM* fm = alloc_nofail(sizeof(WordFM));
555 tl_assert(fm);
556 initFM(fm, alloc_nofail, dealloc, kCmp);
557 return fm;
558}
559
560static void avl_free ( AvlNode* nd,
sewardj250ec2e2008-02-15 22:02:30 +0000561 void(*kFin)(UWord),
562 void(*vFin)(UWord),
sewardjb4112022007-11-09 22:49:28 +0000563 void(*dealloc)(void*) )
564{
565 if (!nd)
566 return;
567 if (nd->child[0])
568 avl_free(nd->child[0], kFin, vFin, dealloc);
569 if (nd->child[1])
570 avl_free(nd->child[1], kFin, vFin, dealloc);
571 if (kFin)
572 kFin( nd->key );
573 if (vFin)
574 vFin( nd->val );
575 VG_(memset)(nd, 0, sizeof(AvlNode));
576 dealloc(nd);
577}
578
579/* Free up the FM. If kFin is non-NULL, it is applied to keys
580 before the FM is deleted; ditto with vFin for vals. */
sewardj250ec2e2008-02-15 22:02:30 +0000581void HG_(deleteFM) ( WordFM* fm, void(*kFin)(UWord), void(*vFin)(UWord) )
sewardjb4112022007-11-09 22:49:28 +0000582{
583 void(*dealloc)(void*) = fm->dealloc;
584 avl_free( fm->root, kFin, vFin, dealloc );
585 VG_(memset)(fm, 0, sizeof(WordFM) );
586 dealloc(fm);
587}
588
589/* Add (k,v) to fm. */
sewardj250ec2e2008-02-15 22:02:30 +0000590void HG_(addToFM) ( WordFM* fm, UWord k, UWord v )
sewardjb4112022007-11-09 22:49:28 +0000591{
592 MaybeWord oldV;
593 AvlNode* node;
594 node = fm->alloc_nofail( sizeof(struct _AvlNode) );
595 node->key = k;
596 node->val = v;
597 oldV.b = False;
598 oldV.w = 0;
599 avl_insert_wrk( &fm->root, &oldV, node, fm->kCmp );
600 //if (oldV.b && fm->vFin)
601 // fm->vFin( oldV.w );
602 if (oldV.b)
603 fm->dealloc(node);
604}
605
606// Delete key from fm, returning associated key and val if found
607Bool HG_(delFromFM) ( WordFM* fm,
sewardj250ec2e2008-02-15 22:02:30 +0000608 /*OUT*/UWord* oldK, /*OUT*/UWord* oldV, UWord key )
sewardjb4112022007-11-09 22:49:28 +0000609{
610 AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
611 if (node) {
612 avl_remove_wrk( &fm->root, node, fm->kCmp );
613 if (oldK)
614 *oldK = node->key;
615 if (oldV)
616 *oldV = node->val;
617 fm->dealloc(node);
618 return True;
619 } else {
620 return False;
621 }
622}
623
624// Look up in fm, assigning found key & val at spec'd addresses
625Bool HG_(lookupFM) ( WordFM* fm,
sewardj250ec2e2008-02-15 22:02:30 +0000626 /*OUT*/UWord* keyP, /*OUT*/UWord* valP, UWord key )
sewardjb4112022007-11-09 22:49:28 +0000627{
628 AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
629 if (node) {
630 if (keyP)
631 *keyP = node->key;
632 if (valP)
633 *valP = node->val;
634 return True;
635 } else {
636 return False;
637 }
638}
639
sewardj250ec2e2008-02-15 22:02:30 +0000640UWord HG_(sizeFM) ( WordFM* fm )
sewardjb4112022007-11-09 22:49:28 +0000641{
642 // Hmm, this is a bad way to do this
643 return fm->root ? size_avl_nonNull( fm->root ) : 0;
644}
645
646// set up FM for iteration
647void HG_(initIterFM) ( WordFM* fm )
648{
649 tl_assert(fm);
650 stackClear(fm);
651 if (fm->root)
652 stackPush(fm, fm->root, 1);
653}
654
sewardj250ec2e2008-02-15 22:02:30 +0000655// set up FM for iteration so that the first key subsequently produced
656// by HG_(nextIterFM) is the smallest key in the map >= start_at.
657// Naturally ">=" is defined by the comparison function supplied to
658// HG_(newFM), as documented above.
659void HG_(initIterAtFM) ( WordFM* fm, UWord start_at )
sewardjae5137e2008-01-17 23:19:54 +0000660{
661 Int i;
662 AvlNode *n, *t;
663 Word cmpresS; /* signed */
664 UWord cmpresU; /* unsigned */
665
666 tl_assert(fm);
667 stackClear(fm);
668
669 if (!fm->root)
670 return;
671
672 n = NULL;
673 // We need to do regular search and fill in the stack.
674 t = fm->root;
675
676 while (True) {
677 if (t == NULL) return;
678
679 cmpresS
680 = fm->kCmp ? /*boxed*/ fm->kCmp( t->key, start_at )
sewardj250ec2e2008-02-15 22:02:30 +0000681 : /*unboxed*/ cmp_unsigned_Words( t->key, start_at );
sewardjae5137e2008-01-17 23:19:54 +0000682
683 if (cmpresS == 0) {
684 // We found the exact key -- we are done.
685 // The iteration should start with this node.
686 stackPush(fm, t, 2);
687 // The stack now looks like {2, 2, ... ,2, 2}
688 return;
689 }
690 cmpresU = (UWord)cmpresS;
691 cmpresU >>=/*unsigned*/ (8 * sizeof(cmpresU) - 1);
692 if (!cmpresU) {
693 // Push this node only if we go to the left child.
694 stackPush(fm, t, 2);
695 }
696 t = t->child[cmpresU];
697 }
698 if (stackPop(fm, &n, &i)) {
699 // If we've pushed something to stack and did not find the exact key,
700 // we must fix the top element of stack.
701 tl_assert(i == 2);
702 stackPush(fm, n, 3);
703 // the stack looks like {2, 2, ..., 2, 3}
704 }
705}
706
sewardjb4112022007-11-09 22:49:28 +0000707// get next key/val pair. Will tl_assert if fm has been modified
sewardjae5137e2008-01-17 23:19:54 +0000708// or looked up in since initIter{,At}FM was called.
sewardj250ec2e2008-02-15 22:02:30 +0000709Bool HG_(nextIterFM) ( WordFM* fm, /*OUT*/UWord* pKey, /*OUT*/UWord* pVal )
sewardjb4112022007-11-09 22:49:28 +0000710{
711 Int i = 0;
712 AvlNode* n = NULL;
713
714 tl_assert(fm);
715
716 // This in-order traversal requires each node to be pushed and popped
717 // three times. These could be avoided by updating nodes in-situ on the
718 // top of the stack, but the push/pop cost is so small that it's worth
719 // keeping this loop in this simpler form.
720 while (stackPop(fm, &n, &i)) {
721 switch (i) {
722 case 1: case_1:
723 stackPush(fm, n, 2);
724 /* if (n->child[0]) stackPush(fm, n->child[0], 1); */
725 if (n->child[0]) { n = n->child[0]; goto case_1; }
726 break;
727 case 2:
728 stackPush(fm, n, 3);
729 if (pKey) *pKey = n->key;
730 if (pVal) *pVal = n->val;
731 return True;
732 case 3:
733 /* if (n->child[1]) stackPush(fm, n->child[1], 1); */
734 if (n->child[1]) { n = n->child[1]; goto case_1; }
735 break;
736 default:
737 tl_assert(0);
738 }
739 }
740
741 // Stack empty, iterator is exhausted, return NULL
742 return False;
743}
744
745// clear the I'm iterating flag
746void HG_(doneIterFM) ( WordFM* fm )
747{
748}
749
sewardj250ec2e2008-02-15 22:02:30 +0000750WordFM* HG_(dopyFM) ( WordFM* fm, UWord(*dopyK)(UWord), UWord(*dopyV)(UWord) )
sewardjb4112022007-11-09 22:49:28 +0000751{
752 WordFM* nyu;
753
754 /* can't clone the fm whilst iterating on it */
755 tl_assert(fm->stackTop == 0);
756
757 nyu = fm->alloc_nofail( sizeof(WordFM) );
758 tl_assert(nyu);
759
760 *nyu = *fm;
761
762 fm->stackTop = 0;
763 VG_(memset)(fm->nodeStack, 0, sizeof(fm->nodeStack));
764 VG_(memset)(fm->numStack, 0, sizeof(fm->numStack));
765
766 if (nyu->root) {
767 nyu->root = avl_dopy( nyu->root, dopyK, dopyV, fm->alloc_nofail );
768 if (! nyu->root)
769 return NULL;
770 }
771
772 return nyu;
773}
774
775//------------------------------------------------------------------//
776//--- end WordFM ---//
777//--- Implementation ---//
778//------------------------------------------------------------------//
779
780//------------------------------------------------------------------//
781//--- WordBag (unboxed words only) ---//
782//--- Implementation ---//
783//------------------------------------------------------------------//
784
785/* A trivial container, to make it opaque. */
786struct _WordBag {
787 WordFM* fm;
788};
789
790WordBag* HG_(newBag) ( void* (*alloc_nofail)( SizeT ),
791 void (*dealloc)(void*) )
792{
793 WordBag* bag = alloc_nofail(sizeof(WordBag));
794 bag->fm = HG_(newFM)( alloc_nofail, dealloc, NULL );
795 return bag;
796}
797
798void HG_(deleteBag) ( WordBag* bag )
799{
800 void (*dealloc)(void*) = bag->fm->dealloc;
801 HG_(deleteFM)( bag->fm, NULL, NULL );
802 VG_(memset)(bag, 0, sizeof(WordBag));
803 dealloc(bag);
804}
805
sewardj250ec2e2008-02-15 22:02:30 +0000806void HG_(addToBag)( WordBag* bag, UWord w )
sewardjb4112022007-11-09 22:49:28 +0000807{
sewardj250ec2e2008-02-15 22:02:30 +0000808 UWord key, count;
sewardjb4112022007-11-09 22:49:28 +0000809 if (HG_(lookupFM)(bag->fm, &key, &count, w)) {
810 tl_assert(key == w);
811 tl_assert(count >= 1);
812 HG_(addToFM)(bag->fm, w, count+1);
813 } else {
814 HG_(addToFM)(bag->fm, w, 1);
815 }
816}
817
sewardj250ec2e2008-02-15 22:02:30 +0000818UWord HG_(elemBag) ( WordBag* bag, UWord w )
sewardjb4112022007-11-09 22:49:28 +0000819{
sewardj250ec2e2008-02-15 22:02:30 +0000820 UWord key, count;
sewardjb4112022007-11-09 22:49:28 +0000821 if (HG_(lookupFM)( bag->fm, &key, &count, w)) {
822 tl_assert(key == w);
823 tl_assert(count >= 1);
824 return count;
825 } else {
826 return 0;
827 }
828}
829
sewardj250ec2e2008-02-15 22:02:30 +0000830UWord HG_(sizeUniqueBag) ( WordBag* bag )
sewardjb4112022007-11-09 22:49:28 +0000831{
832 return HG_(sizeFM)( bag->fm );
833}
834
sewardj250ec2e2008-02-15 22:02:30 +0000835static UWord sizeTotalBag_wrk ( AvlNode* nd )
sewardjb4112022007-11-09 22:49:28 +0000836{
837 /* unchecked pre: nd is non-NULL */
sewardj250ec2e2008-02-15 22:02:30 +0000838 UWord w = nd->val;
sewardjb4112022007-11-09 22:49:28 +0000839 tl_assert(w >= 1);
840 if (nd->child[0])
841 w += sizeTotalBag_wrk(nd->child[0]);
842 if (nd->child[1])
843 w += sizeTotalBag_wrk(nd->child[1]);
844 return w;
845}
sewardj250ec2e2008-02-15 22:02:30 +0000846UWord HG_(sizeTotalBag)( WordBag* bag )
sewardjb4112022007-11-09 22:49:28 +0000847{
848 if (bag->fm->root)
849 return sizeTotalBag_wrk(bag->fm->root);
850 else
851 return 0;
852}
853
sewardj250ec2e2008-02-15 22:02:30 +0000854Bool HG_(delFromBag)( WordBag* bag, UWord w )
sewardjb4112022007-11-09 22:49:28 +0000855{
sewardj250ec2e2008-02-15 22:02:30 +0000856 UWord key, count;
sewardjb4112022007-11-09 22:49:28 +0000857 if (HG_(lookupFM)(bag->fm, &key, &count, w)) {
858 tl_assert(key == w);
859 tl_assert(count >= 1);
860 if (count > 1) {
861 HG_(addToFM)(bag->fm, w, count-1);
862 } else {
863 tl_assert(count == 1);
864 HG_(delFromFM)( bag->fm, NULL, NULL, w );
865 }
866 return True;
867 } else {
868 return False;
869 }
870}
871
872Bool HG_(isEmptyBag)( WordBag* bag )
873{
874 return HG_(sizeFM)(bag->fm) == 0;
875}
876
877Bool HG_(isSingletonTotalBag)( WordBag* bag )
878{
879 AvlNode* nd;
880 if (HG_(sizeFM)(bag->fm) != 1)
881 return False;
882 nd = bag->fm->root;
883 tl_assert(nd);
884 tl_assert(!nd->child[0]);
885 tl_assert(!nd->child[1]);
886 return nd->val == 1;
887}
888
sewardj250ec2e2008-02-15 22:02:30 +0000889UWord HG_(anyElementOfBag)( WordBag* bag )
sewardjb4112022007-11-09 22:49:28 +0000890{
891 /* Return an arbitrarily chosen element in the bag. We might as
892 well return the one at the root of the underlying AVL tree. */
893 AvlNode* nd = bag->fm->root;
894 tl_assert(nd); /* if this fails, 'bag' is empty - caller is in error. */
895 tl_assert(nd->val >= 1);
896 return nd->key;
897}
898
899void HG_(initIterBag)( WordBag* bag )
900{
901 HG_(initIterFM)(bag->fm);
902}
903
sewardj250ec2e2008-02-15 22:02:30 +0000904Bool HG_(nextIterBag)( WordBag* bag, /*OUT*/UWord* pVal, /*OUT*/UWord* pCount )
sewardjb4112022007-11-09 22:49:28 +0000905{
906 return HG_(nextIterFM)( bag->fm, pVal, pCount );
907}
908
909void HG_(doneIterBag)( WordBag* bag )
910{
911 HG_(doneIterFM)( bag->fm );
912}
913
914//------------------------------------------------------------------//
915//--- end WordBag (unboxed words only) ---//
916//--- Implementation ---//
917//------------------------------------------------------------------//
918
sewardjae5137e2008-01-17 23:19:54 +0000919
920#ifdef HG_WORDFM_STANDALONE
921
922//------------------------------------------------------------------//
923//--- Simple test driver. ---//
924//------------------------------------------------------------------//
925
926// We create a map with N values {1, 3, 5, ..., (N*2-1)}
927// and do some trivial stuff with it.
928
929
930// Return the number of elements in range [beg, end).
931// Just lookup for each element in range and count.
932int search_all_elements_in_range_1(WordFM *map, long beg, long end)
933{
sewardj250ec2e2008-02-15 22:02:30 +0000934 long n_found = 0;
935 long i;
936 for (i = beg; i < end; i++) {
937 UWord key, val;
938 if (HG_(lookupFM)(map, &key, &val, (Word)i)) {
sewardjae5137e2008-01-17 23:19:54 +0000939 n_found++;
940 assert(key == -val);
sewardj250ec2e2008-02-15 22:02:30 +0000941 assert(key == (UWord)i);
sewardjae5137e2008-01-17 23:19:54 +0000942 }
943 }
944 return n_found;
945}
946
947// Return the number of elements in range [beg, end).
948// Start with the largest element 'e' such that 'e <= beg'
949// and iterate until 'e < end'.
950int search_all_elements_in_range_2(WordFM *map, long beg, long end)
951{
952 int n_found = 0;
sewardj250ec2e2008-02-15 22:02:30 +0000953 UWord key, val;
sewardjae5137e2008-01-17 23:19:54 +0000954 HG_(initIterAtFM)(map, beg);
sewardj250ec2e2008-02-15 22:02:30 +0000955 while (HG_(nextIterFM)(map, &key, &val) && (long)key < end) {
sewardjae5137e2008-01-17 23:19:54 +0000956 assert(key == -val);
957 n_found++;
958 }
959 HG_(doneIterFM)(map);
960 return n_found;
961}
962
963int main(void)
964{
sewardj250ec2e2008-02-15 22:02:30 +0000965 long i, n = 10;
966 UWord key, val;
967 long beg, end;
sewardjae5137e2008-01-17 23:19:54 +0000968
sewardj250ec2e2008-02-15 22:02:30 +0000969 printf("Create the map, n=%ld\n", n);
sewardjae5137e2008-01-17 23:19:54 +0000970 WordFM *map = HG_(newFM)(malloc, free, NULL/*unboxed Word cmp*/);
971
972 printf("Add keys: ");
973 for(i = 0; i < n; i++) {
974 long val = i * 2 + 1; // 1, 3, 5, ... (n*2-1)
975 printf("%ld ", val);
976 HG_(addToFM)(map, val, -val);
977 }
sewardj250ec2e2008-02-15 22:02:30 +0000978 assert(HG_(sizeFM)(map) == (UWord)n);
sewardjae5137e2008-01-17 23:19:54 +0000979 printf("\n");
980 printf("Iterate elements, size=%d\n", (int)HG_(sizeFM)(map));
981 HG_(initIterFM)(map);
982
sewardj250ec2e2008-02-15 22:02:30 +0000983 while (HG_(nextIterFM(map, &key, &val))) {
sewardjae5137e2008-01-17 23:19:54 +0000984 // int j;
985 // printf("Stack k=%d\n", (int)key);
986 // for(j = map->stackTop-1; j >= 0; j--) {
987 // printf("\t[%d]: k=%d s=%d\n", j,
988 // (int)map->nodeStack[j]->key, (int)map->numStack[j]);
989 // }
990 assert(key == -val);
991 }
992 HG_(doneIterFM)(map);
993
994 printf("Test initIterAtFM\n");
995 for(beg = 0; beg <= n*2; beg++) {
996 HG_(initIterAtFM)(map, (Word)beg);
997 int prev = -1;
sewardj250ec2e2008-02-15 22:02:30 +0000998 printf("StartWith: %ld: ", beg);
sewardjae5137e2008-01-17 23:19:54 +0000999 int n_iter = 0;
1000
1001 while(HG_(nextIterFM(map, &key, &val))) {
1002 printf("%d ", (int)key);
1003 assert(key == -val);
1004 if(prev > 0) assert(prev + 2 == (int)key);
1005 prev = (int)key;
1006 n_iter++;
1007 }
1008 HG_(doneIterFM)(map);
1009
1010 printf("\ntotal: %d\n", n_iter);
1011 if (beg < 1 ) assert(n_iter == n);
1012 else if (beg >= n*2) assert(n_iter == 0);
1013 else assert(n_iter == (n - beg/2));
1014 }
1015
1016 printf("Compare search_all_elements_in_range_[12]\n");
1017 for (beg = 0; beg <= n*2; beg++) {
1018 for (end = 0; end <= n*2; end++) {
1019 assert( search_all_elements_in_range_1(map, beg, end)
1020 == search_all_elements_in_range_2(map, beg, end));
1021 }
1022 }
1023
1024 printf("Delete the map\n");
1025 HG_(deleteFM)(map, NULL, NULL);
1026 printf("Ok!\n");
1027 return 0;
1028}
1029
1030#endif
1031
sewardjb4112022007-11-09 22:49:28 +00001032/*--------------------------------------------------------------------*/
1033/*--- end hg_wordfm.c ---*/
1034/*--------------------------------------------------------------------*/