• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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