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-2017 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, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
30 #include "pub_core_basics.h"
31 #include "pub_core_libcassert.h"
32 #include "pub_core_libcbase.h"
33 #include "pub_core_sparsewa.h" /* self */
35 /////////////////////////////////////////////////////////
37 // SparseWA: Implementation //
39 /////////////////////////////////////////////////////////
41 //////// SWA data structures
43 // (UInt) `echo "Level Zero Byte Map" | md5sum`
44 #define Level0_MAGIC 0x458ec222
46 // (UInt) `echo "Level N Byte Map" | md5sum`
47 #define LevelN_MAGIC 0x0a280a1a
49 /* It's important that the .magic field appears at offset zero in both
50 structs, so that we can reliably distinguish between them. */
64 void* child
[256]; /* either LevelN* or Level0* */
66 Int level
; /* 3 .. 1 on 32-bit, 7 .. 1 on 64-bit */
74 void* curr_nd
; /* LevelN* or Level0* */
75 Int resume_point
; /* 1, 2 or 3 */
80 void* (*alloc_nofail
)(const HChar
*,SizeT
);
82 void (*dealloc
)(void*);
84 SWAStackElem iterStack
[8];
88 //////// SWA helper functions (bitarray)
90 static inline UWord
swa_bitarray_read ( const UChar
* arr
, UWord ix
) {
93 return (arr
[bix
] >> off
) & 1;
96 static inline UWord
swa_bitarray_read_then_set ( UChar
* arr
, UWord ix
) {
100 UChar nyu
= old
| (1 << off
);
102 return (old
>> off
) & 1;
105 static inline UWord
swa_bitarray_read_then_clear ( UChar
* arr
, UWord ix
) {
108 UChar old
= arr
[bix
];
109 UChar nyu
= old
& ~(1 << off
);
111 return (old
>> off
) & 1;
114 //////// SWA helper functions (iteration)
116 static void swa_PUSH ( SparseWA
* swa
, UWord partial_key
, Int curr_ix
,
117 void* curr_nd
, Int resume_point
)
119 Int sp
= swa
->isUsed
;
120 const Int _3_or_7
= sizeof(void*) - 1;
121 // if (0) VG_(printf)("PUSH, old sp = %d\n", sp);
122 vg_assert(sp
>= 0 && sp
<= _3_or_7
);
123 swa
->iterStack
[sp
].partial_key
= partial_key
;
124 swa
->iterStack
[sp
].curr_ix
= curr_ix
;
125 swa
->iterStack
[sp
].curr_nd
= curr_nd
;
126 swa
->iterStack
[sp
].resume_point
= resume_point
;
130 static void swa_POP ( SparseWA
* swa
,
131 UWord
* partial_key
, Int
* curr_ix
,
132 void** curr_nd
, Int
* resume_point
)
134 Int sp
= swa
->isUsed
- 1;
135 const Int _3_or_7
= sizeof(void*) - 1;
136 // if (0) VG_(printf)("POP, old sp = %d\n", sp+1);
137 vg_assert(sp
>= 0 && sp
<= _3_or_7
);
138 *partial_key
= swa
->iterStack
[sp
].partial_key
;
139 *curr_ix
= swa
->iterStack
[sp
].curr_ix
;
140 *curr_nd
= swa
->iterStack
[sp
].curr_nd
;
141 *resume_point
= swa
->iterStack
[sp
].resume_point
;
145 //////// SWA helper functions (allocation)
147 static LevelN
* swa_new_LevelN ( const SparseWA
* swa
, Int level
)
149 LevelN
* levelN
= swa
->alloc_nofail( swa
->cc
, sizeof(LevelN
) );
150 VG_(memset
)(levelN
, 0, sizeof(*levelN
));
151 levelN
->magic
= LevelN_MAGIC
;
152 levelN
->level
= level
;
156 static Level0
* swa_new_Level0 ( const SparseWA
* swa
)
158 Level0
* level0
= swa
->alloc_nofail( swa
->cc
, sizeof(Level0
) );
159 VG_(memset
)(level0
, 0, sizeof(*level0
));
160 level0
->magic
= Level0_MAGIC
;
165 //////// SWA public interface
167 void VG_(initIterSWA
) ( SparseWA
* swa
)
170 if (swa
->root
) swa_PUSH(swa
, 0, 0, swa
->root
, 1/*start_new_node*/);
174 Bool
VG_(nextIterSWA
)( SparseWA
* swa
,
175 /*OUT*/UWord
* keyP
, /*OUT*/UWord
* valP
)
182 /* dispatch whatever's on top of the stack; what that actually
183 means is to return to some previously-saved context. */
186 if (swa
->isUsed
== 0)
189 swa_POP(swa
, &p_key
, &curr_ix
, &curr_nd
, &resume_point
);
190 switch (resume_point
) {
191 case 1: goto start_new_node
;
192 case 2: goto resume_leaf_node
;
193 case 3: goto resume_nonleaf_node
;
194 default: vg_assert(0);
198 if (*(UWord
*)curr_nd
== Level0_MAGIC
) {
199 /* curr_nd is a leaf node */
200 Level0
* level0
= (Level0
*)curr_nd
;
201 for (curr_ix
= 0; curr_ix
< 256; curr_ix
++) {
202 if (swa_bitarray_read(level0
->inUse
, curr_ix
) == 1) {
203 swa_PUSH(swa
, p_key
, curr_ix
, curr_nd
, 2/*resume_leaf_node*/);
204 *keyP
= (p_key
<< 8) + (UWord
)curr_ix
;
205 *valP
= level0
->words
[curr_ix
];
208 level0
= (Level0
*)curr_nd
;
212 /* curr_nd is a non-leaf node */
214 vg_assert(*(UWord
*)curr_nd
== LevelN_MAGIC
);
215 levelN
= (LevelN
*)curr_nd
;
216 for (curr_ix
= 0; curr_ix
< 256; curr_ix
++) {
217 if (levelN
->child
[curr_ix
]) {
218 swa_PUSH(swa
, p_key
, curr_ix
, curr_nd
, 3/*resume_nonleaf_node*/);
219 p_key
= (p_key
<< 8) + (UWord
)curr_ix
;
220 curr_nd
= levelN
->child
[curr_ix
];
223 levelN
= (LevelN
*)curr_nd
;
232 SparseWA
* VG_(newSWA
) ( void*(*alloc_nofail
)(const HChar
* cc
, SizeT
),
234 void(*dealloc
)(void*) )
237 vg_assert(alloc_nofail
);
240 swa
= alloc_nofail( cc
, sizeof(SparseWA
) );
241 VG_(memset
)(swa
, 0, sizeof(*swa
));
242 swa
->alloc_nofail
= alloc_nofail
;
244 swa
->dealloc
= dealloc
;
250 static void swa_deleteSWA_wrk ( void(*dealloc
)(void*), void* nd
)
254 if (*(UWord
*)nd
== LevelN_MAGIC
) {
255 LevelN
* levelN
= (LevelN
*)nd
;
256 for (i
= 0; i
< 256; i
++) {
257 if (levelN
->child
[i
]) {
258 swa_deleteSWA_wrk( dealloc
, levelN
->child
[i
] );
262 vg_assert(*(UWord
*)nd
== Level0_MAGIC
);
266 void VG_(deleteSWA
) ( SparseWA
* swa
)
269 swa_deleteSWA_wrk( swa
->dealloc
, swa
->root
);
274 Bool
VG_(lookupSWA
) ( const SparseWA
* swa
,
282 const Int _3_or_7
= sizeof(void*) - 1;
287 /* levels 3/7 .. 1 */
288 for (i
= _3_or_7
; i
>= 1; i
--) {
289 if (!levelN
) return False
;
290 vg_assert(levelN
->level
== i
);
291 vg_assert(levelN
->nInUse
> 0);
292 ix
= (key
>> (i
*8)) & 0xFF;
293 levelN
= levelN
->child
[ix
];
297 level0
= (Level0
*)levelN
;
298 if (!level0
) return False
;
299 vg_assert(level0
->magic
== Level0_MAGIC
);
300 vg_assert(level0
->nInUse
> 0);
302 if (swa_bitarray_read(level0
->inUse
, ix
) == 0) return False
;
303 *valP
= level0
->words
[ix
];
308 Bool
VG_(addToSWA
) ( SparseWA
* swa
, UWord key
, UWord val
)
314 Bool already_present
;
315 const Int _3_or_7
= sizeof(void*) - 1;
320 swa
->root
= swa_new_LevelN(swa
, _3_or_7
);
323 /* levels 3/7 .. 2 */
324 for (i
= _3_or_7
; i
>= 2; i
--) {
325 /* levelN is the level-i map */
327 vg_assert(levelN
->level
== i
);
328 ix
= (key
>> (i
*8)) & 0xFF;
329 if (levelN
->child
[ix
] == NULL
) {
330 levelN
->child
[ix
] = swa_new_LevelN(swa
, i
-1);
333 vg_assert(levelN
->nInUse
>= 1 && levelN
->nInUse
<= 256);
334 levelN
= levelN
->child
[ix
];
337 /* levelN is the level-1 map */
339 vg_assert(levelN
->level
== 1);
340 ix
= (key
>> (1*8)) & 0xFF;
341 if (levelN
->child
[ix
] == NULL
) {
342 levelN
->child
[ix
] = swa_new_Level0(swa
);
345 vg_assert(levelN
->nInUse
>= 1 && levelN
->nInUse
<= 256);
346 level0
= levelN
->child
[ix
];
348 /* level0 is the level-0 map */
350 vg_assert(level0
->magic
== Level0_MAGIC
);
352 if (swa_bitarray_read_then_set(level0
->inUse
, ix
) == 0) {
354 already_present
= False
;
356 already_present
= True
;
358 vg_assert(level0
->nInUse
>= 1 && level0
->nInUse
<= 256);
359 level0
->words
[ix
] = val
;
361 return already_present
;
365 Bool
VG_(delFromSWA
) ( SparseWA
* swa
,
366 /*OUT*/UWord
* oldV
, UWord key
)
372 const Int _3_or_7
= sizeof(void*) - 1;
374 LevelN
* visited
[_3_or_7
];
375 UWord visitedIx
[_3_or_7
];
381 /* levels 3/7 .. 1 */
382 for (i
= _3_or_7
; i
>= 1; i
--) {
384 if (!levelN
) return False
;
385 vg_assert(levelN
->level
== i
);
386 vg_assert(levelN
->nInUse
> 0);
387 ix
= (key
>> (i
*8)) & 0xFF;
388 visited
[nVisited
] = levelN
;
389 visitedIx
[nVisited
++] = ix
;
390 levelN
= levelN
->child
[ix
];
394 level0
= (Level0
*)levelN
;
395 if (!level0
) return False
;
396 vg_assert(level0
->magic
== Level0_MAGIC
);
397 vg_assert(level0
->nInUse
> 0);
400 if (swa_bitarray_read_then_clear(level0
->inUse
, ix
) == 0)
403 *oldV
= level0
->words
[ix
];
406 if (level0
->nInUse
> 0)
409 vg_assert(nVisited
== _3_or_7
);
410 swa
->dealloc( level0
);
412 /* levels 1 .. 3/7 */
413 for (i
= 1; i
<= _3_or_7
; i
++) {
416 vg_assert(visited
[nVisited
]->child
[ visitedIx
[nVisited
] ]);
417 visited
[nVisited
]->child
[ visitedIx
[nVisited
] ] = NULL
;
418 visited
[nVisited
]->nInUse
--;
419 vg_assert(visited
[nVisited
]->nInUse
>= 0);
420 if (visited
[nVisited
]->nInUse
> 0)
422 swa
->dealloc(visited
[nVisited
]);
425 vg_assert(nVisited
== 0);
431 static UWord
swa_sizeSWA_wrk ( const void* nd
)
434 if (*(const UWord
*)nd
== LevelN_MAGIC
) {
436 const LevelN
* levelN
= nd
;
437 for (i
= 0; i
< 256; i
++) {
438 if (levelN
->child
[i
]) {
439 sum
+= swa_sizeSWA_wrk( levelN
->child
[i
] );
444 const Level0
* level0
;
445 vg_assert(*(const UWord
*)nd
== Level0_MAGIC
);
447 return level0
->nInUse
;
450 UWord
VG_(sizeSWA
) ( const SparseWA
* swa
)
453 return swa_sizeSWA_wrk ( swa
->root
);
460 /*--------------------------------------------------------------------*/
461 /*--- end m_sparsewa.c ---*/
462 /*--------------------------------------------------------------------*/