Add bug 494246 to NEWS
[valgrind.git] / memcheck / tests / unit_oset.c
blobdb9aab6a8b83853d6636e42254921bb7139c3806
2 #include <assert.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
7 #include "pub_core_basics.h"
8 #include "pub_core_libcbase.h"
9 #include "pub_core_libcassert.h"
10 #include "pub_core_libcprint.h"
12 // I need this to avoid some signedness warnings, not sure why
13 // #define Char char
14 // jrs 19 Aug 2005: m_oset.c relies on Char being a signed char.
15 // It appears that plain 'char' on ppc32 is unsigned and so the
16 // above #define screws up the AVL tree balancing logic and
17 // leads to segfaults. Commenting it out and using the standard
18 // definition of Char from pub_core_basics.h seems a good solution
19 // as that has the same signedness on all platforms.
21 // Crudely redirect various VG_(foo)() functions to their libc equivalents.
22 #undef vg_assert
23 #define vg_assert(e) assert(e)
24 #undef vg_assert2
25 #define vg_assert2(e, fmt, args...) assert(e)
27 #define vgPlain_printf printf
28 #define vgPlain_memset memset
29 #define vgPlain_memcpy memcpy
30 #define vgPlain_memmove memmove
31 #define vgPlain_strcmp strcmp
33 // Crudely replace some functions (in m_xarray.c, but not needed for
34 // this unit test) by (hopefully) failing asserts.
35 #define vgPlain_ssort(a,b,c,d) assert(a)
36 #define vgPlain_vcbprintf(a,b,...) assert(a == b)
37 #include "coregrind/m_xarray.c"
38 #undef vgPlain_ssort
39 #undef vgPlain_vcbprintf
40 #include "coregrind/m_poolalloc.c"
41 #include "coregrind/m_oset.c"
43 #define NN 1000 // Size of OSets being created
46 /* Consistent random number generator, so it produces the
47 same results on all platforms. */
49 #define random error_do_not_use_libc_random
51 static UInt seed = 0;
52 static UInt myrandom( void )
54 seed = (1103515245 * seed + 12345);
55 return seed;
58 static void* allocate_node(const HChar* cc, SizeT szB)
59 { return malloc(szB); }
61 static void free_node(void* p)
62 { return free(p); }
65 //---------------------------------------------------------------------------
66 // Word example
67 //---------------------------------------------------------------------------
69 // This example shows that an element can be a single value (in this
70 // case a Word), in which case the element is also the key.
72 __attribute__((unused))
73 static const HChar *wordToStr(const void *p)
75 static HChar buf[32];
76 sprintf(buf, "%ld", *(Word*)p);
77 return buf;
80 __attribute__((unused))
81 static Word wordCmp(void* vkey, void* velem)
83 return *(Word*)vkey - *(Word*)velem;
86 void example1singleset(OSet* oset, char *descr)
88 Int i, n;
89 UWord v, prev;
90 UWord* vs[NN];
91 UWord *pv;
92 UWord sorted_elts[NN]; // Used to test VG_(OSetGen_ResetIterAt)
94 // Try some operations on an empty OSet to ensure they don't screw up.
95 v = 0;
96 vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
97 vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
98 vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
99 vg_assert( ! VG_(OSetGen_Next)(oset) );
100 vg_assert( 0 == VG_(OSetGen_Size)(oset) );
102 // Create some elements, with gaps (they're all even) but no dups,
103 // and shuffle them randomly.
104 for (i = 0; i < NN; i++) {
105 vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Word));
106 *(vs[i]) = 2*(i+1);
107 sorted_elts[i] = *(vs[i]);
109 seed = 0;
110 for (i = 0; i < NN; i++) {
111 UWord r1 = myrandom() % NN;
112 UWord r2 = myrandom() % NN;
113 UWord* tmp= vs[r1];
114 vs[r1] = vs[r2];
115 vs[r2] = tmp;
118 // Insert the elements
119 for (i = 0; i < NN; i++) {
120 VG_(OSetGen_Insert)(oset, vs[i]);
123 // Check the size
124 vg_assert( NN == VG_(OSetGen_Size)(oset) );
126 // Check we can find all the elements we inserted
127 for (i = 0; i < NN; i++) {
128 assert( VG_(OSetGen_Contains)(oset, vs[i]) );
131 #define FULLCHECKEVERY 20
132 // Check VG_(OSetGen_ResetIterAt) works before, at, and after each element.
133 // For some elements, we check all the successive elements.
134 for (i = 0; i < NN; i++) {
135 UWord k;
136 UWord *pval;
137 Int j;
139 // check ResetIterAt just before an elt gives this elt.
140 k = sorted_elts[i] - 1;
141 VG_(OSetGen_ResetIterAt) (oset, &k);
142 // Check all elts till the end
143 for (j = i; j < NN; j++) {
144 pval = VG_(OSetGen_Next)(oset);
145 assert (*pval == sorted_elts[j]);
146 if (i % FULLCHECKEVERY != 0) break;
149 // check ResetIterAt at an elt gives this elt.
150 k = sorted_elts[i];
151 VG_(OSetGen_ResetIterAt) (oset, &k);
152 // Check all elts till the end
153 for (j = i; j < NN; j++) {
154 pval = VG_(OSetGen_Next)(oset);
155 assert (*pval == sorted_elts[j]);
156 if (i % FULLCHECKEVERY != 0) break;
159 // check ResetIterAt after an elt gives the next elt or nothing
160 // when we reset after the last elt.
161 k = sorted_elts[i] + 1;
162 VG_(OSetGen_ResetIterAt) (oset, &k);
163 if (i < NN - 1) {
164 for (j = i+1; j < NN; j++) {
165 pval = VG_(OSetGen_Next)(oset);
166 assert (*pval == sorted_elts[j]);
167 if (i % FULLCHECKEVERY != 0) break;
169 } else {
170 pval = VG_(OSetGen_Next)(oset);
171 assert (pval == NULL);
176 // Check we cannot find elements we did not insert, below, within (odd
177 // numbers), and above the inserted elements.
178 v = 0;
179 assert( ! VG_(OSetGen_Contains)(oset, &v) );
180 for (i = 0; i < NN; i++) {
181 v = *(vs[i]) + 1;
182 assert( ! VG_(OSetGen_Contains)(oset, &v) );
184 v = 2*(NN+1);
185 assert( ! VG_(OSetGen_Contains)(oset, &v) );
187 // Check we can find all the elements we inserted, and the right values
188 // are returned.
189 for (i = 0; i < NN; i++) {
190 assert( vs[i] == VG_(OSetGen_Lookup)(oset, vs[i]) );
193 // Check that we can iterate over the OSet elements in sorted order, and
194 // there is the right number of them.
195 n = 0;
196 pv = NULL;
197 prev = 0;
198 VG_(OSetGen_ResetIter)(oset);
199 while ( (pv = VG_(OSetGen_Next)(oset)) ) {
200 UWord curr = *pv;
201 assert(prev < curr);
202 prev = curr;
203 n++;
205 assert(NN == n);
206 vg_assert( ! VG_(OSetGen_Next)(oset) );
207 vg_assert( ! VG_(OSetGen_Next)(oset) );
209 // Check that we can remove half of the elements, and that their values
210 // are as expected.
211 for (i = 0; i < NN; i += 2) {
212 pv = VG_(OSetGen_Remove)(oset, vs[i]);
213 assert( pv );
214 assert( pv == vs[i] );
217 // Check the size
218 vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
220 // Check we can find the remaining elements (with the right values).
221 for (i = 1; i < NN; i += 2) {
222 pv = VG_(OSetGen_LookupWithCmp)(oset, vs[i], NULL);
223 assert( pv );
224 assert( pv == vs[i] );
227 // Check we cannot find any of the elements we removed.
228 for (i = 0; i < NN; i += 2) {
229 assert( ! VG_(OSetGen_Contains)(oset, vs[i]) );
232 // Check that we can remove the remaining half of the elements, and that
233 // their values are as expected.
234 for (i = 1; i < NN; i += 2) {
235 pv = VG_(OSetGen_Remove)(oset, vs[i]);
236 assert( pv );
237 assert( pv == vs[i] );
240 // Try some more operations on the empty OSet to ensure they don't screw up.
241 vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
242 vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
243 vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
244 vg_assert( ! VG_(OSetGen_Next)(oset) );
245 vg_assert( 0 == VG_(OSetGen_Size)(oset) );
247 // Free a few elements
248 VG_(OSetGen_FreeNode)(oset, vs[0]);
249 VG_(OSetGen_FreeNode)(oset, vs[1]);
250 VG_(OSetGen_FreeNode)(oset, vs[2]);
252 // Re-insert remaining elements, to give OSetGen_Destroy something to
253 // work with.
254 for (i = 3; i < NN; i++) {
255 VG_(OSetGen_Insert)(oset, vs[i]);
258 // Print the list
259 OSet_Print(oset, descr, wordToStr);
263 void example1(void)
265 OSet *oset, *oset_empty_clone;
267 // Create a static OSet of UWords. This one uses fast (built-in)
268 // comparisons.
270 // First a single oset, no pool allocator.
271 oset = VG_(OSetGen_Create)(0,
272 NULL,
273 allocate_node, "oset_test.1", free_node);
274 example1singleset(oset, "single oset, no pool allocator");
276 // Destroy the OSet
277 VG_(OSetGen_Destroy)(oset);
279 // Then same, but with a group allocator
280 oset = VG_(OSetGen_Create_With_Pool)(0,
281 NULL,
282 allocate_node, "oset_test.1",
283 free_node,
284 101, sizeof(Word));
285 example1singleset(oset, "single oset, pool allocator");
287 // Destroy the OSet
288 VG_(OSetGen_Destroy)(oset);
291 // Then two sets, sharing a group allocator.
292 oset = VG_(OSetGen_Create_With_Pool)
294 NULL,
295 allocate_node, "oset_test.1", free_node,
296 101, sizeof(Word));
297 oset_empty_clone = VG_(OSetGen_EmptyClone) (oset);
298 example1singleset(oset, "oset, shared pool");
299 example1singleset(oset_empty_clone, "cloned oset, shared pool");
300 // Destroy both OSet
302 VG_(OSetGen_Destroy)(oset_empty_clone);
303 VG_(OSetGen_Destroy)(oset);
307 void example1b(void)
309 Int i, n;
310 UWord v = 0, prev;
311 UWord vs[NN];
313 // Create a static OSet of UWords. This one uses fast (built-in)
314 // comparisons.
315 OSet* oset = VG_(OSetWord_Create)(allocate_node, "oset_test.2", free_node);
317 // Try some operations on an empty OSet to ensure they don't screw up.
318 vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
319 vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
320 vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
321 vg_assert( 0 == VG_(OSetWord_Size)(oset) );
323 // Create some elements, with gaps (they're all even) but no dups,
324 // and shuffle them randomly.
325 for (i = 0; i < NN; i++) {
326 vs[i] = 2*i;
328 seed = 0;
329 for (i = 0; i < NN; i++) {
330 UWord r1 = myrandom() % NN;
331 UWord r2 = myrandom() % NN;
332 UWord tmp = vs[r1];
333 vs[r1] = vs[r2];
334 vs[r2] = tmp;
337 // Insert the elements
338 for (i = 0; i < NN; i++) {
339 VG_(OSetWord_Insert)(oset, vs[i]);
342 // Check the size
343 vg_assert( NN == VG_(OSetWord_Size)(oset) );
345 // Check we can find all the elements we inserted
346 for (i = 0; i < NN; i++) {
347 assert( VG_(OSetWord_Contains)(oset, vs[i]) );
350 // Check we cannot find elements we did not insert, below, within (odd
351 // numbers), and above the inserted elements.
352 v = 0xffffffff;
353 assert( ! VG_(OSetWord_Contains)(oset, v) );
354 for (i = 0; i < NN; i++) {
355 v = vs[i] + 1;
356 assert( ! VG_(OSetWord_Contains)(oset, v) );
358 v = NN*2;
359 assert( ! VG_(OSetWord_Contains)(oset, v) );
361 // Check we can find all the elements we inserted.
362 for (i = 0; i < NN; i++) {
363 assert( VG_(OSetWord_Contains)(oset, vs[i]) );
366 // Check that we can iterate over the OSet elements in sorted order, and
367 // there is the right number of them.
368 n = 0;
369 prev = 0;
370 VG_(OSetWord_ResetIter)(oset);
371 while ( VG_(OSetWord_Next)(oset, (UWord *)&v) ) {
372 UWord curr = v;
373 if (n == 0)
374 assert(prev == curr);
375 else
376 assert(prev < curr);
377 prev = curr;
378 n++;
380 assert(NN == n);
381 vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
382 vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
384 // Check that we can remove half of the elements.
385 for (i = 0; i < NN; i += 2) {
386 assert( VG_(OSetWord_Remove)(oset, vs[i]) );
389 // Check the size
390 vg_assert( NN/2 == VG_(OSetWord_Size)(oset) );
392 // Check we can find the remaining elements (with the right values).
393 for (i = 1; i < NN; i += 2) {
394 assert( VG_(OSetWord_Contains)(oset, vs[i]) );
397 // Check we cannot find any of the elements we removed.
398 for (i = 0; i < NN; i += 2) {
399 assert( ! VG_(OSetWord_Contains)(oset, vs[i]) );
402 // Check that we can remove the remaining half of the elements.
403 for (i = 1; i < NN; i += 2) {
404 assert( VG_(OSetWord_Remove)(oset, vs[i]) );
407 // Try some more operations on the empty OSet to ensure they don't screw up.
408 vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
409 vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
410 vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
411 vg_assert( 0 == VG_(OSetWord_Size)(oset) );
413 // Re-insert remaining elements, to give OSetWord_Destroy something to
414 // work with.
415 for (i = 3; i < NN; i++) {
416 VG_(OSetWord_Insert)(oset, vs[i]);
419 // Print the list
420 OSet_Print(oset, "oset1b", wordToStr);
422 // Destroy the OSet
423 VG_(OSetWord_Destroy)(oset);
427 //---------------------------------------------------------------------------
428 // Struct example
429 //---------------------------------------------------------------------------
431 // This element shows that a key can be in the middle of the element, and
432 // be of arbitrary size and even span multiple (contiguous) fields. It
433 // also demonstrates how an OSet can be used to implement a list of
434 // non-overlapping intervals.
436 typedef struct {
437 Int b1;
438 RegWord first;
439 RegWord last;
440 Int b2;
442 Block;
444 __attribute__((unused))
445 static HChar *blockToStr(void *p)
447 static HChar buf[32];
448 Block* b = (Block*)p;
449 sprintf(buf, "<(%d) %" FMT_REGWORD "u..%" FMT_REGWORD "u (%d)>",
450 b->b1, b->first, b->last, b->b2);
451 return buf;
454 static Word blockCmp(const void* vkey, const void* velem)
456 RegWord key = *(const RegWord*)vkey;
457 const Block* elem = (const Block*)velem;
459 assert(elem->first <= elem->last);
460 if (key < elem->first) return -1;
461 if (key > elem->last) return 1;
462 return 0;
465 void example2(void)
467 Int i, n;
468 RegWord a;
469 Block* vs[NN];
470 Block v, prev;
471 Block *pv;
473 // Create a dynamic OSet of Blocks. This one uses slow (custom)
474 // comparisons.
475 OSet* oset = VG_(OSetGen_Create)(offsetof(Block, first),
476 blockCmp,
477 allocate_node, "oset_test.3", free_node);
479 // Try some operations on an empty OSet to ensure they don't screw up.
480 vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
481 vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
482 vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
483 vg_assert( ! VG_(OSetGen_Next)(oset) );
484 vg_assert( 0 == VG_(OSetGen_Size)(oset) );
486 // Create some inputs, with gaps -- intervals are 1..3, 11..13, ... -- but
487 // no dups, and shuffle them randomly.
488 for (i = 0; i < NN; i++) {
489 vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Block));
490 vs[i]->b1 = i;
491 vs[i]->first = i*10 + 1;
492 vs[i]->last = vs[i]->first + 2;
493 vs[i]->b2 = i+1;
495 seed = 0;
496 for (i = 0; i < NN; i++) {
497 Int r1 = myrandom() % NN;
498 Int r2 = myrandom() % NN;
499 Block* tmp = vs[r1];
500 vs[r1] = vs[r2];
501 vs[r2] = tmp;
504 // Insert the elements
505 for (i = 0; i < NN; i++) {
506 VG_(OSetGen_Insert)(oset, vs[i]);
509 // Check the size
510 vg_assert( NN == VG_(OSetGen_Size)(oset) );
512 // Check we can find all the elements we inserted, within the full range
513 // of each Block.
514 for (i = 0; i < NN; i++) {
515 a = vs[i]->first + 0; assert( VG_(OSetGen_Contains)(oset, &a) );
516 a = vs[i]->first + 1; assert( VG_(OSetGen_Contains)(oset, &a) );
517 a = vs[i]->first + 2; assert( VG_(OSetGen_Contains)(oset, &a) );
520 // Check we cannot find elements we did not insert, below and above the
521 // ranges of the inserted elements.
522 a = 0;
523 assert( ! VG_(OSetGen_Contains)(oset, &a) );
524 for (i = 0; i < NN; i++) {
525 a = vs[i]->first - 1; assert( ! VG_(OSetGen_Contains)(oset, &a) );
526 a = vs[i]->first + 3; assert( ! VG_(OSetGen_Contains)(oset, &a) );
529 // Check we can find all the elements we inserted, and the right values
530 // are returned.
531 for (i = 0; i < NN; i++) {
532 a = vs[i]->first + 0; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
533 a = vs[i]->first + 1; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
534 a = vs[i]->first + 2; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
535 assert( vs[i] == VG_(OSetGen_LookupWithCmp)(oset, &a, blockCmp) );
538 // Check that we can iterate over the OSet elements in sorted order, and
539 // there is the right number of them.
540 n = 0;
541 pv = NULL;
542 prev.last = 0;
543 VG_(OSetGen_ResetIter)(oset);
544 while ( (pv = VG_(OSetGen_Next)(oset)) ) {
545 Block curr = *pv;
546 assert(prev.last < curr.first);
547 prev = curr;
548 n++;
550 assert(NN == n);
551 vg_assert( ! VG_(OSetGen_Next)(oset) );
552 vg_assert( ! VG_(OSetGen_Next)(oset) );
554 // Check that we can remove half of the elements, and that their values
555 // are as expected.
556 for (i = 0; i < NN; i += 2) {
557 a = vs[i]->first; assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
560 // Check the size
561 vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
563 // Check we can find the remaining elements (with the right values).
564 for (i = 1; i < NN; i += 2) {
565 a = vs[i]->first + 0; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
566 a = vs[i]->first + 1; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
567 a = vs[i]->first + 2; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
570 // Check we cannot find any of the elements we removed.
571 for (i = 0; i < NN; i += 2) {
572 a = vs[i]->first + 0; assert( ! VG_(OSetGen_Contains)(oset, &a) );
573 a = vs[i]->first + 1; assert( ! VG_(OSetGen_Contains)(oset, &a) );
574 a = vs[i]->first + 2; assert( ! VG_(OSetGen_Contains)(oset, &a) );
577 // Check that we can remove the remaining half of the elements, and that
578 // their values are as expected.
579 for (i = 1; i < NN; i += 2) {
580 a = vs[i]->first; assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
583 // Try some more operations on the empty OSet to ensure they don't screw up.
584 vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
585 vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
586 vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
587 vg_assert( ! VG_(OSetGen_Next)(oset) );
588 vg_assert( 0 == VG_(OSetGen_Size)(oset) );
590 // Re-insert all elements, to give OSetGen_Destroy something to work with.
591 for (i = 0; i < NN; i++) {
592 VG_(OSetGen_Insert)(oset, vs[i]);
595 // Destroy the OSet
596 VG_(OSetGen_Destroy)(oset);
599 //-----------------------------------------------------------------------
600 // main()
601 //-----------------------------------------------------------------------
603 int main(void)
605 example1();
606 example1b();
607 example2();
608 return 0;