summaryrefslogtreecommitdiff
path: root/pjlib/src/pjlib-test/rbtree.c
blob: 475ce0c171388ad59a0d96bb6b9fbc17e2b23a78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* $Id$
 */
#include "test.h"

#if INCLUDE_RBTREE_TEST

#include <pjlib.h>

#define LOOP	    32
#define MIN_COUNT   64
#define MAX_COUNT   (LOOP * MIN_COUNT)
#define STRSIZE	    16
#define THIS_FILE   "rbtree_test"

typedef struct node_key
{
    pj_uint32_t hash;
    char str[STRSIZE];
} node_key;

static int compare_node(const node_key *k1, const node_key *k2)
{
    if (k1->hash == k2->hash) {
	return strcmp(k1->str, k2->str);
    } else {
	return k1->hash	< k2->hash ? -1 : 1;
    }
}

void randomize_string(char *str, int len)
{
    int i;
    for (i=0; i<len-1; ++i)
	str[i] = (char)('a' + pj_rand() % 26);
    str[len-1] = '\0';
}

static int test(void)
{
    pj_rbtree rb;
    node_key *key;
    pj_rbtree_node *node;
    pj_pool_t *pool;
    int err=0;
    int count = MIN_COUNT;
    int i;
    unsigned size;

    pj_rbtree_init(&rb, (pj_rbtree_comp*)&compare_node);
    size = MAX_COUNT*(sizeof(*key)+PJ_RBTREE_NODE_SIZE) + 
			   PJ_RBTREE_SIZE + PJ_POOL_SIZE;
    pool = pj_pool_create( mem, "pool", size, 0, NULL);
    if (!pool) {
	PJ_LOG(3,("test", "...error: creating pool of %u bytes", size));
	return -10;
    }

    key = (node_key *)pj_pool_alloc(pool, MAX_COUNT*sizeof(*key));
    if (!key)
	return -20;

    node = (pj_rbtree_node*)pj_pool_alloc(pool, MAX_COUNT*sizeof(*node));
    if (!node)
	return -30;

    for (i=0; i<LOOP; ++i) {
	int j;
	pj_rbtree_node *prev, *it;
	pj_timestamp t1, t2, t_setup, t_insert, t_search, t_erase;

	pj_assert(rb.size == 0);

	t_setup.u32.lo = t_insert.u32.lo = t_search.u32.lo = t_erase.u32.lo = 0;

	for (j=0; j<count; j++) {
	    randomize_string(key[j].str, STRSIZE);

	    pj_get_timestamp(&t1);
	    node[j].key = &key[j];
	    node[j].user_data = key[j].str;
	    key[j].hash = pj_hash_calc(0, key[j].str, PJ_HASH_KEY_STRING);
	    pj_get_timestamp(&t2);
	    t_setup.u32.lo += (t2.u32.lo - t1.u32.lo);

	    pj_get_timestamp(&t1);
	    pj_rbtree_insert(&rb, &node[j]);
	    pj_get_timestamp(&t2);
	    t_insert.u32.lo += (t2.u32.lo - t1.u32.lo);
	}

	pj_assert(rb.size == (unsigned)count);

	// Iterate key, make sure they're sorted.
	prev = NULL;
	it = pj_rbtree_first(&rb);
	while (it) {
	    if (prev) {
		if (compare_node((node_key*)prev->key,(node_key*)it->key)>=0) {
		    ++err;
		    PJ_LOG(3, (THIS_FILE, "Error: %s >= %s", 
			       (char*)prev->user_data, (char*)it->user_data));
		}
	    }
	    prev = it;
	    it = pj_rbtree_next(&rb, it);
	}

	// Search.
	for (j=0; j<count; j++) {
	    pj_get_timestamp(&t1);
	    it = pj_rbtree_find(&rb, &key[j]);
	    pj_get_timestamp(&t2);
	    t_search.u32.lo += (t2.u32.lo - t1.u32.lo);

	    pj_assert(it != NULL);
	    if (it == NULL)
		++err;
	}

	// Erase node.
	for (j=0; j<count; j++) {
	    pj_get_timestamp(&t1);
	    it = pj_rbtree_erase(&rb, &node[j]);
	    pj_get_timestamp(&t2);
	    t_erase.u32.lo += (t2.u32.lo - t1.u32.lo);
	}

	PJ_LOG(4, (THIS_FILE, 
		"...count:%d, setup:%d, insert:%d, search:%d, erase:%d",
		count,
		t_setup.u32.lo / count, t_insert.u32.lo / count,
		t_search.u32.lo / count, t_erase.u32.lo / count));

	count = 2 * count;
	if (count > MAX_COUNT)
	    break;
    }

    pj_pool_release(pool);
    return err;
}


int rbtree_test()
{
    return test();
}

#endif	/* INCLUDE_RBTREE_TEST */