#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pub_core_basics.h"
#include "pub_core_libcbase.h"
#include "pub_core_libcassert.h"
#include "pub_core_libcprint.h"
// I need this to avoid some signedness warnings, not sure why
// #define Char char
// jrs 19 Aug 2005: m_oset.c relies on Char being a signed char.
// It appears that plain 'char' on ppc32 is unsigned and so the
// above #define screws up the AVL tree balancing logic and
// leads to segfaults. Commenting it out and using the standard
// definition of Char from pub_core_basics.h seems a good solution
// as that has the same signedness on all platforms.
// Crudely redirect various VG_(foo)() functions to their libc equivalents.
#undef vg_assert
#define vg_assert(e) assert(e)
#undef vg_assert2
#define vg_assert2(e, fmt, args...) assert(e)
#define vgPlain_printf printf
#define vgPlain_memset memset
#define vgPlain_memcpy memcpy
#include "coregrind/m_oset.c"
#define NN 1000 // Size of OSets being created
/* Consistent random number generator, so it produces the
same results on all platforms. */
#define random error_do_not_use_libc_random
static UInt seed = 0;
static UInt myrandom( void )
{
seed = (1103515245 * seed + 12345);
return seed;
}
static void* allocate_node(HChar* cc, SizeT szB)
{ return malloc(szB); }
static void free_node(void* p)
{ return free(p); }
//---------------------------------------------------------------------------
// Word example
//---------------------------------------------------------------------------
// This example shows that an element can be a single value (in this
// case a Word), in which case the element is also the key.
__attribute__((unused))
static Char *wordToStr(void *p)
{
static char buf[32];
sprintf(buf, "%ld", *(Word*)p);
return buf;
}
__attribute__((unused))
static Word wordCmp(void* vkey, void* velem)
{
return *(Word*)vkey - *(Word*)velem;
}
void example1(void)
{
Int i, n;
Word v, prev;
Word* vs[NN];
Word *pv;
// Create a static OSet of Ints. This one uses fast (built-in)
// comparisons.
OSet* oset = VG_(OSetGen_Create)(0,
NULL,
allocate_node, "oset_test.1", free_node);
// Try some operations on an empty OSet to ensure they don't screw up.
vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
vg_assert( ! VG_(OSetGen_Next)(oset) );
vg_assert( 0 == VG_(OSetGen_Size)(oset) );
// Create some elements, with gaps (they're all even) but no dups,
// and shuffle them randomly.
for (i = 0; i < NN; i++) {
vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Word));
*(vs[i]) = 2*i;
}
seed = 0;
for (i = 0; i < NN; i++) {
Word r1 = myrandom() % NN;
Word r2 = myrandom() % NN;
Word* tmp= vs[r1];
vs[r1] = vs[r2];
vs[r2] = tmp;
}
// Insert the elements
for (i = 0; i < NN; i++) {
VG_(OSetGen_Insert)(oset, vs[i]);
}
// Check the size
vg_assert( NN == VG_(OSetGen_Size)(oset) );
// Check we can find all the elements we inserted
for (i = 0; i < NN; i++) {
assert( VG_(OSetGen_Contains)(oset, vs[i]) );
}
// Check we cannot find elements we did not insert, below, within (odd
// numbers), and above the inserted elements.
v = -1;
assert( ! VG_(OSetGen_Contains)(oset, &v) );
for (i = 0; i < NN; i++) {
v = *(vs[i]) + 1;
assert( ! VG_(OSetGen_Contains)(oset, &v) );
}
v = NN*2;
assert( ! VG_(OSetGen_Contains)(oset, &v) );
// Check we can find all the elements we inserted, and the right values
// are returned.
for (i = 0; i < NN; i++) {
assert( vs[i] == VG_(OSetGen_Lookup)(oset, vs[i]) );
}
// Check that we can iterate over the OSet elements in sorted order, and
// there is the right number of them.
n = 0;
pv = NULL;
prev = -1;
VG_(OSetGen_ResetIter)(oset);
while ( (pv = VG_(OSetGen_Next)(oset)) ) {
Word curr = *pv;
assert(prev < curr);
prev = curr;
n++;
}
assert(NN == n);
vg_assert( ! VG_(OSetGen_Next)(oset) );
vg_assert( ! VG_(OSetGen_Next)(oset) );
// Check that we can remove half of the elements, and that their values
// are as expected.
for (i = 0; i < NN; i += 2) {
assert( pv = VG_(OSetGen_Remove)(oset, vs[i]) );
assert( pv == vs[i] );
}
// Check the size
vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
// Check we can find the remaining elements (with the right values).
for (i = 1; i < NN; i += 2) {
assert( pv = VG_(OSetGen_LookupWithCmp)(oset, vs[i], NULL) );
assert( pv == vs[i] );
}
// Check we cannot find any of the elements we removed.
for (i = 0; i < NN; i += 2) {
assert( ! VG_(OSetGen_Contains)(oset, vs[i]) );
}
// Check that we can remove the remaining half of the elements, and that
// their values are as expected.
for (i = 1; i < NN; i += 2) {
assert( pv = VG_(OSetGen_Remove)(oset, vs[i]) );
assert( pv == vs[i] );
}
// Try some more operations on the empty OSet to ensure they don't screw up.
vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
vg_assert( ! VG_(OSetGen_Next)(oset) );
vg_assert( 0 == VG_(OSetGen_Size)(oset) );
// Free a few elements
VG_(OSetGen_FreeNode)(oset, vs[0]);
VG_(OSetGen_FreeNode)(oset, vs[1]);
VG_(OSetGen_FreeNode)(oset, vs[2]);
// Re-insert remaining elements, to give OSetGen_Destroy something to
// work with.
for (i = 3; i < NN; i++) {
VG_(OSetGen_Insert)(oset, vs[i]);
}
// Print the list
OSet_Print(oset, "oset1", wordToStr);
// Destroy the OSet
VG_(OSetGen_Destroy)(oset);
}
void example1b(void)
{
Int i, n;
Word v = 0, prev;
Word vs[NN];
// Create a static OSet of Ints. This one uses fast (built-in)
// comparisons.
OSet* oset = VG_(OSetWord_Create)(allocate_node, "oset_test.2", free_node);
// Try some operations on an empty OSet to ensure they don't screw up.
vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
vg_assert( ! VG_(OSetWord_Next)(oset, &v) );
vg_assert( 0 == VG_(OSetWord_Size)(oset) );
// Create some elements, with gaps (they're all even) but no dups,
// and shuffle them randomly.
for (i = 0; i < NN; i++) {
vs[i] = 2*i;
}
seed = 0;
for (i = 0; i < NN; i++) {
Word r1 = myrandom() % NN;
Word r2 = myrandom() % NN;
Word tmp = vs[r1];
vs[r1] = vs[r2];
vs[r2] = tmp;
}
// Insert the elements
for (i = 0; i < NN; i++) {
VG_(OSetWord_Insert)(oset, vs[i]);
}
// Check the size
vg_assert( NN == VG_(OSetWord_Size)(oset) );
// Check we can find all the elements we inserted
for (i = 0; i < NN; i++) {
assert( VG_(OSetWord_Contains)(oset, vs[i]) );
}
// Check we cannot find elements we did not insert, below, within (odd
// numbers), and above the inserted elements.
v = -1;
assert( ! VG_(OSetWord_Contains)(oset, v) );
for (i = 0; i < NN; i++) {
v = vs[i] + 1;
assert( ! VG_(OSetWord_Contains)(oset, v) );
}
v = NN*2;
assert( ! VG_(OSetWord_Contains)(oset, v) );
// Check we can find all the elements we inserted.
for (i = 0; i < NN; i++) {
assert( VG_(OSetWord_Contains)(oset, vs[i]) );
}
// Check that we can iterate over the OSet elements in sorted order, and
// there is the right number of them.
n = 0;
prev = -1;
VG_(OSetWord_ResetIter)(oset);
while ( VG_(OSetWord_Next)(oset, &v) ) {
Word curr = v;
assert(prev < curr);
prev = curr;
n++;
}
assert(NN == n);
vg_assert( ! VG_(OSetWord_Next)(oset, &v) );
vg_assert( ! VG_(OSetWord_Next)(oset, &v) );
// Check that we can remove half of the elements.
for (i = 0; i < NN; i += 2) {
assert( VG_(OSetWord_Remove)(oset, vs[i]) );
}
// Check the size
vg_assert( NN/2 == VG_(OSetWord_Size)(oset) );
// Check we can find the remaining elements (with the right values).
for (i = 1; i < NN; i += 2) {
assert( VG_(OSetWord_Contains)(oset, vs[i]) );
}
// Check we cannot find any of the elements we removed.
for (i = 0; i < NN; i += 2) {
assert( ! VG_(OSetWord_Contains)(oset, vs[i]) );
}
// Check that we can remove the remaining half of the elements.
for (i = 1; i < NN; i += 2) {
assert( VG_(OSetWord_Remove)(oset, vs[i]) );
}
// Try some more operations on the empty OSet to ensure they don't screw up.
vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
vg_assert( ! VG_(OSetWord_Next)(oset, &v) );
vg_assert( 0 == VG_(OSetWord_Size)(oset) );
// Re-insert remaining elements, to give OSetWord_Destroy something to
// work with.
for (i = 3; i < NN; i++) {
VG_(OSetWord_Insert)(oset, vs[i]);
}
// Print the list
OSet_Print(oset, "oset1b", wordToStr);
// Destroy the OSet
VG_(OSetWord_Destroy)(oset);
}
//---------------------------------------------------------------------------
// Struct example
//---------------------------------------------------------------------------
// This element shows that a key can be in the middle of the element, and
// be of arbitrary size and even span multiple (contiguous) fields. It
// also demonstrates how an OSet can be used to implement a list of
// non-overlapping intervals.
typedef struct {
Int b1;
Addr first;
Addr last;
Int b2;
}
Block;
__attribute__((unused))
static Char *blockToStr(void *p)
{
static char buf[32];
Block* b = (Block*)p;
sprintf(buf, "<(%d) %lu..%lu (%d)>", b->b1, b->first, b->last, b->b2);
return buf;
}
static Word blockCmp(const void* vkey, const void* velem)
{
Addr key = *(const Addr*)vkey;
const Block* elem = (const Block*)velem;
assert(elem->first <= elem->last);
if (key < elem->first) return -1;
if (key > elem->last) return 1;
return 0;
}
void example2(void)
{
Int i, n;
Addr a;
Block* vs[NN];
Block v, prev;
Block *pv;
// Create a dynamic OSet of Blocks. This one uses slow (custom)
// comparisons.
OSet* oset = VG_(OSetGen_Create)(offsetof(Block, first),
blockCmp,
allocate_node, "oset_test.3", free_node);
// Try some operations on an empty OSet to ensure they don't screw up.
vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
vg_assert( ! VG_(OSetGen_Next)(oset) );
vg_assert( 0 == VG_(OSetGen_Size)(oset) );
// Create some inputs, with gaps -- intervals are 1..3, 11..13, ... -- but
// no dups, and shuffle them randomly.
for (i = 0; i < NN; i++) {
vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Block));
vs[i]->b1 = i;
vs[i]->first = i*10 + 1;
vs[i]->last = vs[i]->first + 2;
vs[i]->b2 = i+1;
}
seed = 0;
for (i = 0; i < NN; i++) {
Int r1 = myrandom() % NN;
Int r2 = myrandom() % NN;
Block* tmp = vs[r1];
vs[r1] = vs[r2];
vs[r2] = tmp;
}
// Insert the elements
for (i = 0; i < NN; i++) {
VG_(OSetGen_Insert)(oset, vs[i]);
}
// Check the size
vg_assert( NN == VG_(OSetGen_Size)(oset) );
// Check we can find all the elements we inserted, within the full range
// of each Block.
for (i = 0; i < NN; i++) {
a = vs[i]->first + 0; assert( VG_(OSetGen_Contains)(oset, &a) );
a = vs[i]->first + 1; assert( VG_(OSetGen_Contains)(oset, &a) );
a = vs[i]->first + 2; assert( VG_(OSetGen_Contains)(oset, &a) );
}
// Check we cannot find elements we did not insert, below and above the
// ranges of the inserted elements.
a = 0;
assert( ! VG_(OSetGen_Contains)(oset, &a) );
for (i = 0; i < NN; i++) {
a = vs[i]->first - 1; assert( ! VG_(OSetGen_Contains)(oset, &a) );
a = vs[i]->first + 3; assert( ! VG_(OSetGen_Contains)(oset, &a) );
}
// Check we can find all the elements we inserted, and the right values
// are returned.
for (i = 0; i < NN; i++) {
a = vs[i]->first + 0; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
a = vs[i]->first + 1; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
a = vs[i]->first + 2; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
assert( vs[i] == VG_(OSetGen_LookupWithCmp)(oset, &a, blockCmp) );
}
// Check that we can iterate over the OSet elements in sorted order, and
// there is the right number of them.
n = 0;
pv = NULL;
prev.last = 0;
VG_(OSetGen_ResetIter)(oset);
while ( (pv = VG_(OSetGen_Next)(oset)) ) {
Block curr = *pv;
assert(prev.last < curr.first);
prev = curr;
n++;
}
assert(NN == n);
vg_assert( ! VG_(OSetGen_Next)(oset) );
vg_assert( ! VG_(OSetGen_Next)(oset) );
// Check that we can remove half of the elements, and that their values
// are as expected.
for (i = 0; i < NN; i += 2) {
a = vs[i]->first; assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
}
// Check the size
vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
// Check we can find the remaining elements (with the right values).
for (i = 1; i < NN; i += 2) {
a = vs[i]->first + 0; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
a = vs[i]->first + 1; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
a = vs[i]->first + 2; assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
}
// Check we cannot find any of the elements we removed.
for (i = 0; i < NN; i += 2) {
a = vs[i]->first + 0; assert( ! VG_(OSetGen_Contains)(oset, &a) );
a = vs[i]->first + 1; assert( ! VG_(OSetGen_Contains)(oset, &a) );
a = vs[i]->first + 2; assert( ! VG_(OSetGen_Contains)(oset, &a) );
}
// Check that we can remove the remaining half of the elements, and that
// their values are as expected.
for (i = 1; i < NN; i += 2) {
a = vs[i]->first; assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
}
// Try some more operations on the empty OSet to ensure they don't screw up.
vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
vg_assert( ! VG_(OSetGen_Next)(oset) );
vg_assert( 0 == VG_(OSetGen_Size)(oset) );
// Re-insert all elements, to give OSetGen_Destroy something to work with.
for (i = 0; i < NN; i++) {
VG_(OSetGen_Insert)(oset, vs[i]);
}
// Destroy the OSet
VG_(OSetGen_Destroy)(oset);
}
//-----------------------------------------------------------------------
// main()
//-----------------------------------------------------------------------
int main(void)
{
example1();
example1b();
example2();
return 0;
}