2 /*--------------------------------------------------------------------*/
3 /*--- An sparse array (of words) implementation. ---*/
4 /*--- m_sparsewa.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2008-2013 OpenWorks Ltd
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 The GNU General Public License is contained in the file COPYING.
32 #include "pub_core_basics.h"
33 #include "pub_core_libcassert.h"
34 #include "pub_core_libcbase.h"
35 #include "pub_core_sparsewa.h" /* self */
37 /////////////////////////////////////////////////////////
39 // SparseWA: Implementation //
41 /////////////////////////////////////////////////////////
43 //////// SWA data structures
45 // (UInt) `echo "Level Zero Byte Map" | md5sum`
46 #define Level0_MAGIC 0x458ec222
48 // (UInt) `echo "Level N Byte Map" | md5sum`
49 #define LevelN_MAGIC 0x0a280a1a
51 /* It's important that the .magic field appears at offset zero in both
52 structs, so that we can reliably distinguish between them. */
66 void* child
[256]; /* either LevelN* or Level0* */
68 Int level
; /* 3 .. 1 on 32-bit, 7 .. 1 on 64-bit */
76 void* curr_nd
; /* LevelN* or Level0* */
77 Int resume_point
; /* 1, 2 or 3 */
82 void* (*alloc_nofail
)(const HChar
*,SizeT
);
84 void (*dealloc
)(void*);
86 SWAStackElem iterStack
[8];
90 //////// SWA helper functions (bitarray)
92 static inline UWord
swa_bitarray_read ( const UChar
* arr
, UWord ix
) {
95 return (arr
[bix
] >> off
) & 1;
98 static inline UWord
swa_bitarray_read_then_set ( UChar
* arr
, UWord ix
) {
101 UChar old
= arr
[bix
];
102 UChar nyu
= old
| (1 << off
);
104 return (old
>> off
) & 1;
107 static inline UWord
swa_bitarray_read_then_clear ( UChar
* arr
, UWord ix
) {
110 UChar old
= arr
[bix
];
111 UChar nyu
= old
& ~(1 << off
);
113 return (old
>> off
) & 1;
116 //////// SWA helper functions (iteration)
118 static void swa_PUSH ( SparseWA
* swa
, UWord partial_key
, Int curr_ix
,
119 void* curr_nd
, Int resume_point
)
121 Int sp
= swa
->isUsed
;
122 const Int _3_or_7
= sizeof(void*) - 1;
123 // if (0) VG_(printf)("PUSH, old sp = %d\n", sp);
124 vg_assert(sp
>= 0 && sp
<= _3_or_7
);
125 swa
->iterStack
[sp
].partial_key
= partial_key
;
126 swa
->iterStack
[sp
].curr_ix
= curr_ix
;
127 swa
->iterStack
[sp
].curr_nd
= curr_nd
;
128 swa
->iterStack
[sp
].resume_point
= resume_point
;
132 static void swa_POP ( SparseWA
* swa
,
133 UWord
* partial_key
, Int
* curr_ix
,
134 void** curr_nd
, Int
* resume_point
)
136 Int sp
= swa
->isUsed
- 1;
137 const Int _3_or_7
= sizeof(void*) - 1;
138 // if (0) VG_(printf)("POP, old sp = %d\n", sp+1);
139 vg_assert(sp
>= 0 && sp
<= _3_or_7
);
140 *partial_key
= swa
->iterStack
[sp
].partial_key
;
141 *curr_ix
= swa
->iterStack
[sp
].curr_ix
;
142 *curr_nd
= swa
->iterStack
[sp
].curr_nd
;
143 *resume_point
= swa
->iterStack
[sp
].resume_point
;
147 //////// SWA helper functions (allocation)
149 static LevelN
* swa_new_LevelN ( const SparseWA
* swa
, Int level
)
151 LevelN
* levelN
= swa
->alloc_nofail( swa
->cc
, sizeof(LevelN
) );
152 VG_(memset
)(levelN
, 0, sizeof(*levelN
));
153 levelN
->magic
= LevelN_MAGIC
;
154 levelN
->level
= level
;
158 static Level0
* swa_new_Level0 ( const SparseWA
* swa
)
160 Level0
* level0
= swa
->alloc_nofail( swa
->cc
, sizeof(Level0
) );
161 VG_(memset
)(level0
, 0, sizeof(*level0
));
162 level0
->magic
= Level0_MAGIC
;
167 //////// SWA public interface
169 void VG_(initIterSWA
) ( SparseWA
* swa
)
172 if (swa
->root
) swa_PUSH(swa
, 0, 0, swa
->root
, 1/*start_new_node*/);
176 Bool
VG_(nextIterSWA
)( SparseWA
* swa
,
177 /*OUT*/UWord
* keyP
, /*OUT*/UWord
* valP
)
184 /* dispatch whatever's on top of the stack; what that actually
185 means is to return to some previously-saved context. */
188 if (swa
->isUsed
== 0)
191 swa_POP(swa
, &p_key
, &curr_ix
, &curr_nd
, &resume_point
);
192 switch (resume_point
) {
193 case 1: goto start_new_node
;
194 case 2: goto resume_leaf_node
;
195 case 3: goto resume_nonleaf_node
;
196 default: vg_assert(0);
200 if (*(UWord
*)curr_nd
== Level0_MAGIC
) {
201 /* curr_nd is a leaf node */
202 Level0
* level0
= (Level0
*)curr_nd
;
203 for (curr_ix
= 0; curr_ix
< 256; curr_ix
++) {
204 if (swa_bitarray_read(level0
->inUse
, curr_ix
) == 1) {
205 swa_PUSH(swa
, p_key
, curr_ix
, curr_nd
, 2/*resume_leaf_node*/);
206 *keyP
= (p_key
<< 8) + (UWord
)curr_ix
;
207 *valP
= level0
->words
[curr_ix
];
210 level0
= (Level0
*)curr_nd
;
214 /* curr_nd is a non-leaf node */
216 vg_assert(*(UWord
*)curr_nd
== LevelN_MAGIC
);
217 levelN
= (LevelN
*)curr_nd
;
218 for (curr_ix
= 0; curr_ix
< 256; curr_ix
++) {
219 if (levelN
->child
[curr_ix
]) {
220 swa_PUSH(swa
, p_key
, curr_ix
, curr_nd
, 3/*resume_nonleaf_node*/);
221 p_key
= (p_key
<< 8) + (UWord
)curr_ix
;
222 curr_nd
= levelN
->child
[curr_ix
];
225 levelN
= (LevelN
*)curr_nd
;
234 SparseWA
* VG_(newSWA
) ( void*(*alloc_nofail
)(const HChar
* cc
, SizeT
),
236 void(*dealloc
)(void*) )
239 vg_assert(alloc_nofail
);
242 swa
= alloc_nofail( cc
, sizeof(SparseWA
) );
243 VG_(memset
)(swa
, 0, sizeof(*swa
));
244 swa
->alloc_nofail
= alloc_nofail
;
246 swa
->dealloc
= dealloc
;
252 static void swa_deleteSWA_wrk ( void(*dealloc
)(void*), void* nd
)
256 if (*(UWord
*)nd
== LevelN_MAGIC
) {
257 LevelN
* levelN
= (LevelN
*)nd
;
258 for (i
= 0; i
< 256; i
++) {
259 if (levelN
->child
[i
]) {
260 swa_deleteSWA_wrk( dealloc
, levelN
->child
[i
] );
264 vg_assert(*(UWord
*)nd
== Level0_MAGIC
);
268 void VG_(deleteSWA
) ( SparseWA
* swa
)
271 swa_deleteSWA_wrk( swa
->dealloc
, swa
->root
);
276 Bool
VG_(lookupSWA
) ( const SparseWA
* swa
,
277 /*OUT*/UWord
* keyP
, /*OUT*/UWord
* valP
,
284 const Int _3_or_7
= sizeof(void*) - 1;
289 /* levels 3/7 .. 1 */
290 for (i
= _3_or_7
; i
>= 1; i
--) {
291 if (!levelN
) return False
;
292 vg_assert(levelN
->level
== i
);
293 vg_assert(levelN
->nInUse
> 0);
294 ix
= (key
>> (i
*8)) & 0xFF;
295 levelN
= levelN
->child
[ix
];
299 level0
= (Level0
*)levelN
;
300 if (!level0
) return False
;
301 vg_assert(level0
->magic
== Level0_MAGIC
);
302 vg_assert(level0
->nInUse
> 0);
304 if (swa_bitarray_read(level0
->inUse
, ix
) == 0) return False
;
305 *keyP
= key
; /* this is stupid. only here to make it look like WordFM */
306 *valP
= level0
->words
[ix
];
311 Bool
VG_(addToSWA
) ( SparseWA
* swa
, UWord key
, UWord val
)
317 Bool already_present
;
318 const Int _3_or_7
= sizeof(void*) - 1;
323 swa
->root
= swa_new_LevelN(swa
, _3_or_7
);
326 /* levels 3/7 .. 2 */
327 for (i
= _3_or_7
; i
>= 2; i
--) {
328 /* levelN is the level-i map */
330 vg_assert(levelN
->level
== i
);
331 ix
= (key
>> (i
*8)) & 0xFF;
332 if (levelN
->child
[ix
] == NULL
) {
333 levelN
->child
[ix
] = swa_new_LevelN(swa
, i
-1);
336 vg_assert(levelN
->nInUse
>= 1 && levelN
->nInUse
<= 256);
337 levelN
= levelN
->child
[ix
];
340 /* levelN is the level-1 map */
342 vg_assert(levelN
->level
== 1);
343 ix
= (key
>> (1*8)) & 0xFF;
344 if (levelN
->child
[ix
] == NULL
) {
345 levelN
->child
[ix
] = swa_new_Level0(swa
);
348 vg_assert(levelN
->nInUse
>= 1 && levelN
->nInUse
<= 256);
349 level0
= levelN
->child
[ix
];
351 /* level0 is the level-0 map */
353 vg_assert(level0
->magic
== Level0_MAGIC
);
355 if (swa_bitarray_read_then_set(level0
->inUse
, ix
) == 0) {
357 already_present
= False
;
359 already_present
= True
;
361 vg_assert(level0
->nInUse
>= 1 && level0
->nInUse
<= 256);
362 level0
->words
[ix
] = val
;
364 return already_present
;
368 Bool
VG_(delFromSWA
) ( SparseWA
* swa
,
369 /*OUT*/UWord
* oldK
, /*OUT*/UWord
* oldV
, UWord key
)
375 const Int _3_or_7
= sizeof(void*) - 1;
377 LevelN
* visited
[_3_or_7
];
378 UWord visitedIx
[_3_or_7
];
384 /* levels 3/7 .. 1 */
385 for (i
= _3_or_7
; i
>= 1; i
--) {
387 if (!levelN
) return False
;
388 vg_assert(levelN
->level
== i
);
389 vg_assert(levelN
->nInUse
> 0);
390 ix
= (key
>> (i
*8)) & 0xFF;
391 visited
[nVisited
] = levelN
;
392 visitedIx
[nVisited
++] = ix
;
393 levelN
= levelN
->child
[ix
];
397 level0
= (Level0
*)levelN
;
398 if (!level0
) return False
;
399 vg_assert(level0
->magic
== Level0_MAGIC
);
400 vg_assert(level0
->nInUse
> 0);
403 if (swa_bitarray_read_then_clear(level0
->inUse
, ix
) == 0)
406 *oldK
= key
; /* this is silly */
407 *oldV
= level0
->words
[ix
];
410 if (level0
->nInUse
> 0)
413 vg_assert(nVisited
== _3_or_7
);
414 swa
->dealloc( level0
);
416 /* levels 1 .. 3/7 */
417 for (i
= 1; i
<= _3_or_7
; i
++) {
420 vg_assert(visited
[nVisited
]->child
[ visitedIx
[nVisited
] ]);
421 visited
[nVisited
]->child
[ visitedIx
[nVisited
] ] = NULL
;
422 visited
[nVisited
]->nInUse
--;
423 vg_assert(visited
[nVisited
]->nInUse
>= 0);
424 if (visited
[nVisited
]->nInUse
> 0)
426 swa
->dealloc(visited
[nVisited
]);
429 vg_assert(nVisited
== 0);
435 static UWord
swa_sizeSWA_wrk ( const void* nd
)
438 if (*(const UWord
*)nd
== LevelN_MAGIC
) {
440 const LevelN
* levelN
= nd
;
441 for (i
= 0; i
< 256; i
++) {
442 if (levelN
->child
[i
]) {
443 sum
+= swa_sizeSWA_wrk( levelN
->child
[i
] );
448 const Level0
* level0
;
449 vg_assert(*(const UWord
*)nd
== Level0_MAGIC
);
451 return level0
->nInUse
;
454 UWord
VG_(sizeSWA
) ( const SparseWA
* swa
)
457 return swa_sizeSWA_wrk ( swa
->root
);
464 /*--------------------------------------------------------------------*/
465 /*--- end m_sparsewa.c ---*/
466 /*--------------------------------------------------------------------*/