1
2 #include <assert.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include "pub_core_basics.h"
8 #include "pub_core_libcbase.h"
9 #include "pub_core_libcassert.h"
10 #include "pub_core_libcprint.h"
11
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.
20
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)
26
27 #define vgPlain_printf printf
28 #define vgPlain_memset memset
29 #define vgPlain_memcpy memcpy
30 #define vgPlain_memmove memmove
31
32 // Crudely replace some functions (in m_xarray.c, but not needed for
33 // this unit test) by (hopefully) failing asserts.
34 #define vgPlain_ssort(a,b,c,d) assert(a)
35 #define vgPlain_vcbprintf(a,b,...) assert(a == b)
36 #include "coregrind/m_xarray.c"
37 #undef vgPlain_ssort
38 #undef vgPlain_vcbprintf
39 #include "coregrind/m_poolalloc.c"
40 #include "coregrind/m_oset.c"
41
42 #define NN 1000 // Size of OSets being created
43
44
45 /* Consistent random number generator, so it produces the
46 same results on all platforms. */
47
48 #define random error_do_not_use_libc_random
49
50 static UInt seed = 0;
myrandom(void)51 static UInt myrandom( void )
52 {
53 seed = (1103515245 * seed + 12345);
54 return seed;
55 }
56
allocate_node(HChar * cc,SizeT szB)57 static void* allocate_node(HChar* cc, SizeT szB)
58 { return malloc(szB); }
59
free_node(void * p)60 static void free_node(void* p)
61 { return free(p); }
62
63
64 //---------------------------------------------------------------------------
65 // Word example
66 //---------------------------------------------------------------------------
67
68 // This example shows that an element can be a single value (in this
69 // case a Word), in which case the element is also the key.
70
71 __attribute__((unused))
wordToStr(void * p)72 static Char *wordToStr(void *p)
73 {
74 static char buf[32];
75 sprintf(buf, "%ld", *(Word*)p);
76 return buf;
77 }
78
79 __attribute__((unused))
wordCmp(void * vkey,void * velem)80 static Word wordCmp(void* vkey, void* velem)
81 {
82 return *(Word*)vkey - *(Word*)velem;
83 }
84
example1singleset(OSet * oset,char * descr)85 void example1singleset(OSet* oset, char *descr)
86 {
87 Int i, n;
88 Word v, prev;
89 Word* vs[NN];
90 Word *pv;
91
92 // Try some operations on an empty OSet to ensure they don't screw up.
93 vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
94 vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
95 vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
96 vg_assert( ! VG_(OSetGen_Next)(oset) );
97 vg_assert( 0 == VG_(OSetGen_Size)(oset) );
98
99 // Create some elements, with gaps (they're all even) but no dups,
100 // and shuffle them randomly.
101 for (i = 0; i < NN; i++) {
102 vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Word));
103 *(vs[i]) = 2*i;
104 }
105 seed = 0;
106 for (i = 0; i < NN; i++) {
107 Word r1 = myrandom() % NN;
108 Word r2 = myrandom() % NN;
109 Word* tmp= vs[r1];
110 vs[r1] = vs[r2];
111 vs[r2] = tmp;
112 }
113
114 // Insert the elements
115 for (i = 0; i < NN; i++) {
116 VG_(OSetGen_Insert)(oset, vs[i]);
117 }
118
119 // Check the size
120 vg_assert( NN == VG_(OSetGen_Size)(oset) );
121
122 // Check we can find all the elements we inserted
123 for (i = 0; i < NN; i++) {
124 assert( VG_(OSetGen_Contains)(oset, vs[i]) );
125 }
126
127 // Check we cannot find elements we did not insert, below, within (odd
128 // numbers), and above the inserted elements.
129 v = -1;
130 assert( ! VG_(OSetGen_Contains)(oset, &v) );
131 for (i = 0; i < NN; i++) {
132 v = *(vs[i]) + 1;
133 assert( ! VG_(OSetGen_Contains)(oset, &v) );
134 }
135 v = NN*2;
136 assert( ! VG_(OSetGen_Contains)(oset, &v) );
137
138 // Check we can find all the elements we inserted, and the right values
139 // are returned.
140 for (i = 0; i < NN; i++) {
141 assert( vs[i] == VG_(OSetGen_Lookup)(oset, vs[i]) );
142 }
143
144 // Check that we can iterate over the OSet elements in sorted order, and
145 // there is the right number of them.
146 n = 0;
147 pv = NULL;
148 prev = -1;
149 VG_(OSetGen_ResetIter)(oset);
150 while ( (pv = VG_(OSetGen_Next)(oset)) ) {
151 Word curr = *pv;
152 assert(prev < curr);
153 prev = curr;
154 n++;
155 }
156 assert(NN == n);
157 vg_assert( ! VG_(OSetGen_Next)(oset) );
158 vg_assert( ! VG_(OSetGen_Next)(oset) );
159
160 // Check that we can remove half of the elements, and that their values
161 // are as expected.
162 for (i = 0; i < NN; i += 2) {
163 assert( pv = VG_(OSetGen_Remove)(oset, vs[i]) );
164 assert( pv == vs[i] );
165 }
166
167 // Check the size
168 vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
169
170 // Check we can find the remaining elements (with the right values).
171 for (i = 1; i < NN; i += 2) {
172 assert( pv = VG_(OSetGen_LookupWithCmp)(oset, vs[i], NULL) );
173 assert( pv == vs[i] );
174 }
175
176 // Check we cannot find any of the elements we removed.
177 for (i = 0; i < NN; i += 2) {
178 assert( ! VG_(OSetGen_Contains)(oset, vs[i]) );
179 }
180
181 // Check that we can remove the remaining half of the elements, and that
182 // their values are as expected.
183 for (i = 1; i < NN; i += 2) {
184 assert( pv = VG_(OSetGen_Remove)(oset, vs[i]) );
185 assert( pv == vs[i] );
186 }
187
188 // Try some more operations on the empty OSet to ensure they don't screw up.
189 vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
190 vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
191 vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
192 vg_assert( ! VG_(OSetGen_Next)(oset) );
193 vg_assert( 0 == VG_(OSetGen_Size)(oset) );
194
195 // Free a few elements
196 VG_(OSetGen_FreeNode)(oset, vs[0]);
197 VG_(OSetGen_FreeNode)(oset, vs[1]);
198 VG_(OSetGen_FreeNode)(oset, vs[2]);
199
200 // Re-insert remaining elements, to give OSetGen_Destroy something to
201 // work with.
202 for (i = 3; i < NN; i++) {
203 VG_(OSetGen_Insert)(oset, vs[i]);
204 }
205
206 // Print the list
207 OSet_Print(oset, descr, wordToStr);
208
209 }
210
example1(void)211 void example1(void)
212 {
213 OSet *oset, *oset_empty_clone;
214
215 // Create a static OSet of Ints. This one uses fast (built-in)
216 // comparisons.
217
218 // First a single oset, no pool allocator.
219 oset = VG_(OSetGen_Create)(0,
220 NULL,
221 allocate_node, "oset_test.1", free_node);
222 example1singleset(oset, "single oset, no pool allocator");
223
224 // Destroy the OSet
225 VG_(OSetGen_Destroy)(oset);
226
227 // Then same, but with a group allocator
228 oset = VG_(OSetGen_Create_With_Pool)(0,
229 NULL,
230 allocate_node, "oset_test.1",
231 free_node,
232 101, sizeof(Word));
233 example1singleset(oset, "single oset, pool allocator");
234
235 // Destroy the OSet
236 VG_(OSetGen_Destroy)(oset);
237
238
239 // Then two sets, sharing a group allocator.
240 oset = VG_(OSetGen_Create_With_Pool)
241 (0,
242 NULL,
243 allocate_node, "oset_test.1", free_node,
244 101, sizeof(Word));
245 oset_empty_clone = VG_(OSetGen_EmptyClone) (oset);
246 example1singleset(oset, "oset, shared pool");
247 example1singleset(oset_empty_clone, "cloned oset, shared pool");
248 // Destroy both OSet
249
250 VG_(OSetGen_Destroy)(oset_empty_clone);
251 VG_(OSetGen_Destroy)(oset);
252
253 }
254
example1b(void)255 void example1b(void)
256 {
257 Int i, n;
258 Word v = 0, prev;
259 Word vs[NN];
260
261 // Create a static OSet of Ints. This one uses fast (built-in)
262 // comparisons.
263 OSet* oset = VG_(OSetWord_Create)(allocate_node, "oset_test.2", free_node);
264
265 // Try some operations on an empty OSet to ensure they don't screw up.
266 vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
267 vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
268 vg_assert( ! VG_(OSetWord_Next)(oset, &v) );
269 vg_assert( 0 == VG_(OSetWord_Size)(oset) );
270
271 // Create some elements, with gaps (they're all even) but no dups,
272 // and shuffle them randomly.
273 for (i = 0; i < NN; i++) {
274 vs[i] = 2*i;
275 }
276 seed = 0;
277 for (i = 0; i < NN; i++) {
278 Word r1 = myrandom() % NN;
279 Word r2 = myrandom() % NN;
280 Word tmp = vs[r1];
281 vs[r1] = vs[r2];
282 vs[r2] = tmp;
283 }
284
285 // Insert the elements
286 for (i = 0; i < NN; i++) {
287 VG_(OSetWord_Insert)(oset, vs[i]);
288 }
289
290 // Check the size
291 vg_assert( NN == VG_(OSetWord_Size)(oset) );
292
293 // Check we can find all the elements we inserted
294 for (i = 0; i < NN; i++) {
295 assert( VG_(OSetWord_Contains)(oset, vs[i]) );
296 }
297
298 // Check we cannot find elements we did not insert, below, within (odd
299 // numbers), and above the inserted elements.
300 v = -1;
301 assert( ! VG_(OSetWord_Contains)(oset, v) );
302 for (i = 0; i < NN; i++) {
303 v = vs[i] + 1;
304 assert( ! VG_(OSetWord_Contains)(oset, v) );
305 }
306 v = NN*2;
307 assert( ! VG_(OSetWord_Contains)(oset, v) );
308
309 // Check we can find all the elements we inserted.
310 for (i = 0; i < NN; i++) {
311 assert( VG_(OSetWord_Contains)(oset, vs[i]) );
312 }
313
314 // Check that we can iterate over the OSet elements in sorted order, and
315 // there is the right number of them.
316 n = 0;
317 prev = -1;
318 VG_(OSetWord_ResetIter)(oset);
319 while ( VG_(OSetWord_Next)(oset, &v) ) {
320 Word curr = v;
321 assert(prev < curr);
322 prev = curr;
323 n++;
324 }
325 assert(NN == n);
326 vg_assert( ! VG_(OSetWord_Next)(oset, &v) );
327 vg_assert( ! VG_(OSetWord_Next)(oset, &v) );
328
329 // Check that we can remove half of the elements.
330 for (i = 0; i < NN; i += 2) {
331 assert( VG_(OSetWord_Remove)(oset, vs[i]) );
332 }
333
334 // Check the size
335 vg_assert( NN/2 == VG_(OSetWord_Size)(oset) );
336
337 // Check we can find the remaining elements (with the right values).
338 for (i = 1; i < NN; i += 2) {
339 assert( VG_(OSetWord_Contains)(oset, vs[i]) );
340 }
341
342 // Check we cannot find any of the elements we removed.
343 for (i = 0; i < NN; i += 2) {
344 assert( ! VG_(OSetWord_Contains)(oset, vs[i]) );
345 }
346
347 // Check that we can remove the remaining half of the elements.
348 for (i = 1; i < NN; i += 2) {
349 assert( VG_(OSetWord_Remove)(oset, vs[i]) );
350 }
351
352 // Try some more operations on the empty OSet to ensure they don't screw up.
353 vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
354 vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
355 vg_assert( ! VG_(OSetWord_Next)(oset, &v) );
356 vg_assert( 0 == VG_(OSetWord_Size)(oset) );
357
358 // Re-insert remaining elements, to give OSetWord_Destroy something to
359 // work with.
360 for (i = 3; i < NN; i++) {
361 VG_(OSetWord_Insert)(oset, vs[i]);
362 }
363
364 // Print the list
365 OSet_Print(oset, "oset1b", wordToStr);
366
367 // Destroy the OSet
368 VG_(OSetWord_Destroy)(oset);
369 }
370
371
372 //---------------------------------------------------------------------------
373 // Struct example
374 //---------------------------------------------------------------------------
375
376 // This element shows that a key can be in the middle of the element, and
377 // be of arbitrary size and even span multiple (contiguous) fields. It
378 // also demonstrates how an OSet can be used to implement a list of
379 // non-overlapping intervals.
380
381 typedef struct {
382 Int b1;
383 Addr first;
384 Addr last;
385 Int b2;
386 }
387 Block;
388
389 __attribute__((unused))
blockToStr(void * p)390 static Char *blockToStr(void *p)
391 {
392 static char buf[32];
393 Block* b = (Block*)p;
394 sprintf(buf, "<(%d) %lu..%lu (%d)>", b->b1, b->first, b->last, b->b2);
395 return buf;
396 }
397
blockCmp(const void * vkey,const void * velem)398 static Word blockCmp(const void* vkey, const void* velem)
399 {
400 Addr key = *(const Addr*)vkey;
401 const Block* elem = (const Block*)velem;
402
403 assert(elem->first <= elem->last);
404 if (key < elem->first) return -1;
405 if (key > elem->last) return 1;
406 return 0;
407 }
408
example2(void)409 void example2(void)
410 {
411 Int i, n;
412 Addr a;
413 Block* vs[NN];
414 Block v, prev;
415 Block *pv;
416
417 // Create a dynamic OSet of Blocks. This one uses slow (custom)
418 // comparisons.
419 OSet* oset = VG_(OSetGen_Create)(offsetof(Block, first),
420 blockCmp,
421 allocate_node, "oset_test.3", free_node);
422
423 // Try some operations on an empty OSet to ensure they don't screw up.
424 vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
425 vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
426 vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
427 vg_assert( ! VG_(OSetGen_Next)(oset) );
428 vg_assert( 0 == VG_(OSetGen_Size)(oset) );
429
430 // Create some inputs, with gaps -- intervals are 1..3, 11..13, ... -- but
431 // no dups, and shuffle them randomly.
432 for (i = 0; i < NN; i++) {
433 vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Block));
434 vs[i]->b1 = i;
435 vs[i]->first = i*10 + 1;
436 vs[i]->last = vs[i]->first + 2;
437 vs[i]->b2 = i+1;
438 }
439 seed = 0;
440 for (i = 0; i < NN; i++) {
441 Int r1 = myrandom() % NN;
442 Int r2 = myrandom() % NN;
443 Block* tmp = vs[r1];
444 vs[r1] = vs[r2];
445 vs[r2] = tmp;
446 }
447
448 // Insert the elements
449 for (i = 0; i < NN; i++) {
450 VG_(OSetGen_Insert)(oset, vs[i]);
451 }
452
453 // Check the size
454 vg_assert( NN == VG_(OSetGen_Size)(oset) );
455
456 // Check we can find all the elements we inserted, within the full range
457 // of each Block.
458 for (i = 0; i < NN; i++) {
459 a = vs[i]->first + 0; assert( VG_(OSetGen_Contains)(oset, &a) );
460 a = vs[i]->first + 1; assert( VG_(OSetGen_Contains)(oset, &a) );
461 a = vs[i]->first + 2; assert( VG_(OSetGen_Contains)(oset, &a) );
462 }
463
464 // Check we cannot find elements we did not insert, below and above the
465 // ranges of the inserted elements.
466 a = 0;
467 assert( ! VG_(OSetGen_Contains)(oset, &a) );
468 for (i = 0; i < NN; i++) {
469 a = vs[i]->first - 1; assert( ! VG_(OSetGen_Contains)(oset, &a) );
470 a = vs[i]->first + 3; assert( ! VG_(OSetGen_Contains)(oset, &a) );
471 }
472
473 // Check we can find all the elements we inserted, and the right values
474 // are returned.
475 for (i = 0; i < NN; i++) {
476 a = vs[i]->first + 0; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
477 a = vs[i]->first + 1; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
478 a = vs[i]->first + 2; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
479 assert( vs[i] == VG_(OSetGen_LookupWithCmp)(oset, &a, blockCmp) );
480 }
481
482 // Check that we can iterate over the OSet elements in sorted order, and
483 // there is the right number of them.
484 n = 0;
485 pv = NULL;
486 prev.last = 0;
487 VG_(OSetGen_ResetIter)(oset);
488 while ( (pv = VG_(OSetGen_Next)(oset)) ) {
489 Block curr = *pv;
490 assert(prev.last < curr.first);
491 prev = curr;
492 n++;
493 }
494 assert(NN == n);
495 vg_assert( ! VG_(OSetGen_Next)(oset) );
496 vg_assert( ! VG_(OSetGen_Next)(oset) );
497
498 // Check that we can remove half of the elements, and that their values
499 // are as expected.
500 for (i = 0; i < NN; i += 2) {
501 a = vs[i]->first; assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
502 }
503
504 // Check the size
505 vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
506
507 // Check we can find the remaining elements (with the right values).
508 for (i = 1; i < NN; i += 2) {
509 a = vs[i]->first + 0; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
510 a = vs[i]->first + 1; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
511 a = vs[i]->first + 2; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
512 }
513
514 // Check we cannot find any of the elements we removed.
515 for (i = 0; i < NN; i += 2) {
516 a = vs[i]->first + 0; assert( ! VG_(OSetGen_Contains)(oset, &a) );
517 a = vs[i]->first + 1; assert( ! VG_(OSetGen_Contains)(oset, &a) );
518 a = vs[i]->first + 2; assert( ! VG_(OSetGen_Contains)(oset, &a) );
519 }
520
521 // Check that we can remove the remaining half of the elements, and that
522 // their values are as expected.
523 for (i = 1; i < NN; i += 2) {
524 a = vs[i]->first; assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
525 }
526
527 // Try some more operations on the empty OSet to ensure they don't screw up.
528 vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
529 vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
530 vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
531 vg_assert( ! VG_(OSetGen_Next)(oset) );
532 vg_assert( 0 == VG_(OSetGen_Size)(oset) );
533
534 // Re-insert all elements, to give OSetGen_Destroy something to work with.
535 for (i = 0; i < NN; i++) {
536 VG_(OSetGen_Insert)(oset, vs[i]);
537 }
538
539 // Destroy the OSet
540 VG_(OSetGen_Destroy)(oset);
541 }
542
543 //-----------------------------------------------------------------------
544 // main()
545 //-----------------------------------------------------------------------
546
main(void)547 int main(void)
548 {
549 example1();
550 example1b();
551 example2();
552 return 0;
553 }
554