9
#define DEFAULT_MAX_TEST (500)
10
hash_entry_t *iter_result_1 = NULL;
11
hash_entry_t *iter_result_2 = NULL;
13
unsigned long max_test = DEFAULT_MAX_TEST;
16
const char *error_string(int error)
18
if (IS_HASH_ERROR(error))
19
return hash_error_string(error);
21
return strerror(error);
24
char *key_string(hash_key_t *key)
26
static char buf[1024];
30
snprintf(buf, sizeof(buf), "key ulong = %lu", key->ul);
33
snprintf(buf, sizeof(buf), "key string = \"%s\"", key->str);
36
snprintf(buf, sizeof(buf), "unknown key type = %d", key->type);
42
char *value_string(hash_value_t *value)
44
static char buf[1024];
47
case HASH_VALUE_UNDEF:
48
snprintf(buf, sizeof(buf), "value undefined");
51
snprintf(buf, sizeof(buf), "value str = \"%s\"", (char *)value->ptr);
54
snprintf(buf, sizeof(buf), "value int = %d", value->i);
57
snprintf(buf, sizeof(buf), "value unsigned int = %u", value->ui);
60
snprintf(buf, sizeof(buf), "value long = %ld", value->l);
62
case HASH_VALUE_ULONG:
63
snprintf(buf, sizeof(buf), "value unsigned long = %lu", value->ul);
65
case HASH_VALUE_FLOAT:
66
snprintf(buf, sizeof(buf), "value float = %f", value->f);
68
case HASH_VALUE_DOUBLE:
69
snprintf(buf, sizeof(buf), "value double = %f", value->f);
72
snprintf(buf, sizeof(buf), "unknown value type = %d", value->type);
79
char *entry_string(hash_entry_t *entry)
81
static char buf[1024];
83
snprintf(buf, sizeof(buf), "[%s] = [%s]", key_string(&entry->key), value_string(&entry->value));
89
bool callback(hash_entry_t *item, void *user_data)
91
unsigned long *callback_count = (unsigned long *)user_data;
93
iter_result_1[*callback_count] = *item;
97
if (verbose) printf("%s\n", entry_string(item));
101
void delete_callback(hash_entry_t *item, hash_destroy_enum type, void *pvt)
103
if (item->value.type == HASH_VALUE_PTR) free(item->value.ptr);
106
typedef struct test_val_t {
112
int main(int argc, char **argv)
114
test_val_t *test = NULL;
120
hash_table_t *table = NULL;
121
unsigned long callback_count = 0;
122
unsigned int directory_bits = HASH_DEFAULT_DIRECTORY_BITS;
123
unsigned int segment_bits = HASH_DEFAULT_SEGMENT_BITS;
124
unsigned long min_load_factor = HASH_DEFAULT_MIN_LOAD_FACTOR;
125
unsigned long max_load_factor = HASH_DEFAULT_MAX_LOAD_FACTOR;
129
int option_index = 0;
130
static struct option long_options[] = {
131
{"count", 1, 0, 'c'},
132
{"verbose", 1, 0, 'v'},
133
{"quiet", 1, 0, 'q'},
134
{"directory-bits", 1, 0, 'd'},
135
{"segment-bits", 1, 0, 's'},
136
{"min-load-factor", 1, 0, 'l'},
137
{"max-load-factor", 1, 0, 'h'},
141
arg = getopt_long(argc, argv, "c:vqd:s:l:h:",
142
long_options, &option_index);
143
if (arg == -1) break;
147
max_test = atol(optarg);
156
directory_bits = atoi(optarg);
159
segment_bits = atoi(optarg);
162
min_load_factor = atol(optarg);
165
max_load_factor = atol(optarg);
170
if ((test = (test_val_t *) calloc(max_test, sizeof(test_val_t))) == NULL) {
171
fprintf(stderr, "Failed to allocate test array\n");
174
if ((iter_result_1 = (hash_entry_t *) calloc(max_test, sizeof(hash_entry_t))) == NULL) {
175
fprintf(stderr, "Failed to allocate iter_result_1 array\n");
178
if ((iter_result_2 = (hash_entry_t *) calloc(max_test, sizeof(hash_entry_t))) == NULL) {
179
fprintf(stderr, "Failed to allocate iter_result_2 array\n");
184
/* Initialize the random number generator */
187
/* Create the hash table as small as possible to exercise growth */
188
if ((status = hash_create_ex(1, &table,
189
directory_bits, segment_bits,
190
min_load_factor, max_load_factor,
192
delete_callback, NULL)) != HASH_SUCCESS) {
193
fprintf(stderr, "table creation failed at line %d (%s)\n", __LINE__, error_string(status));
197
/* Initialize the array of test values */
198
for (i = 0; i < max_test; i++) {
199
test[i].val = random();
200
/* If the value is odd we'll use a string as the key,
201
* otherwise we'll use an unsigned long as the key */
202
if (test[i].val & 1) {
203
key.type = HASH_KEY_STRING;
204
sprintf(buf, "%ld", test[i].val);
205
test[i].str = strdup(buf);
209
/* Enter all the test values into the hash table */
210
for (i = 0; i < max_test; i++) {
211
if (test[i].val & 1) {
212
key.type = HASH_KEY_STRING;
213
key.str = test[i].str;
214
value.type = HASH_VALUE_PTR;
215
value.ptr = (void *) strdup(test[i].str);
218
key.type = HASH_KEY_ULONG;
219
key.ul = test[i].val;
220
value.type = HASH_VALUE_LONG;
221
value.l = test[i].val;
224
if (hash_has_key(table, &key)) {
225
fprintf(stderr, "Error: %ld already in table when inserting, i = %lu, at line %d\n",
226
test[i].val, i, __LINE__);
229
if ((status = hash_enter(table, &key, &value)) != HASH_SUCCESS) {
230
fprintf(stderr, "Error: %ld failed insertion at line %d (%s) \n",
231
test[i].val, __LINE__, error_string(status));
236
/* Now visit each entry in the table using a callback iterator,
237
* store what we found in iter_result_1 for testing the iterator object later on */
238
if (verbose) printf("callback iterate:\n");
240
if ((status = hash_iterate(table, callback, &callback_count)) != HASH_SUCCESS) {
241
fprintf(stderr, "hash_iterate failed at line %d (%s)\n", __LINE__, error_string(status));
244
if (verbose) printf("hash_count=%ld, callback_count=%ld\n", hash_count(table), callback_count);
246
if (hash_count(table) != callback_count) {
247
fprintf(stderr, "Error: hash_count(%ld) != callback_count(%ld) at line %d\n",
248
hash_count(table), callback_count, __LINE__);
252
/* Now vist each entry in the table using an iterator object */
254
struct hash_iter_context_t *iter;
255
unsigned long n_items;
258
if (verbose) printf("iter iterate:\n");
261
iter = new_hash_iter_context(table);
263
while ((entry = iter->next(iter)) != NULL) {
264
if (verbose) printf("%s\n", entry_string(entry));
265
iter_result_2[n_items] = *entry;
268
if (verbose) printf("hash_count=%ld, n_items=%ld\n", hash_count(table), n_items);
270
if (hash_count(table) != n_items) {
271
fprintf(stderr, "Error: hash_count(%ld) != n_items(%ld) at line %d\n",
272
hash_count(table), n_items, __LINE__);
278
/* Both iterators should have visited each item in the same order, verify ... */
279
for (i = 0; i < max_test; i++) {
280
if (memcmp(&iter_result_1[i], &iter_result_2[i], sizeof(iter_result_1[0])) != 0) {
281
fprintf(stderr, "Error: iter_result_1[%lu] != iter_result_2[%lu] at line %d\n",
287
/* Get an array of keys in the table, print them out */
292
if (verbose) printf("\nhash_keys:\n");
293
if ((status = hash_keys(table, &count, &keys)) != HASH_SUCCESS) {
294
fprintf(stderr, "hash_keys failed at line %d (%s)\n",
295
__LINE__, error_string(status));
299
if (hash_count(table) != count) {
300
fprintf(stderr, "Error: hash_count(%ld) != hash_keys() count(%ld) at line %d\n",
301
hash_count(table), count, __LINE__);
305
for (i = 0; i < count; i++) {
306
if (verbose) printf("%s\n", key_string(&keys[i]));
311
/* Get an array of values in the table, print them out */
314
hash_value_t *values;
316
if (verbose) printf("\nhash_values:\n");
317
hash_values(table, &count, &values);
319
if (hash_count(table) != count) {
320
fprintf(stderr, "Error: hash_count(%ld) != hash_values() count(%ld) at line %d\n",
321
hash_count(table), count, __LINE__);
325
for (i = 0; i < count; i++) {
326
if (verbose) printf("%s\n", value_string(&values[i]));
331
/* Get an array of items in the table, print them out */
334
hash_entry_t *entries;
336
if (verbose) printf("\nhash_entries:\n");
337
hash_entries(table, &count, &entries);
339
if (hash_count(table) != count) {
340
fprintf(stderr, "Error: hash_count(%ld) != hash_entries() count(%ld) at line %d\n",
341
hash_count(table), count, __LINE__);
345
for (i = 0; i < count; i++) {
346
if (verbose) printf("%s\n", entry_string(&entries[i]));
351
/* See if we can find every key */
352
for (i = max_test - 1; i >= 0; i--) {
353
if (test[i].val & 1) {
354
key.type = HASH_KEY_STRING;
355
key.str = test[i].str;
358
key.type = HASH_KEY_ULONG;
359
key.ul = test[i].val;
361
if ((status = hash_lookup(table, &key, &value)) != HASH_SUCCESS) {
362
fprintf(stderr, "Error: failed first lookup for value %ld at index %ld at line %d (%s)\n",
363
test[i].val, i, __LINE__, error_string(status));
369
if (strcmp((char *)value.ptr, test[i].str) != 0) {
370
fprintf(stderr, "Error: corrupt ptr data for %lu at line %d\n", i, __LINE__);
374
case HASH_VALUE_LONG:
375
if (value.l != test[i].val) {
376
fprintf(stderr, "Error: corrupt long data for %lu at line %d\n", i, __LINE__);
381
fprintf(stderr, "Error: unknown value type for %lu\n", i);
389
* Delete a key, make sure we can't find it, assure we can find all other
392
for (i = 0; i < max_test; i++) {
393
if (test[i].val & 1) {
394
key.type = HASH_KEY_STRING;
395
key.str = test[i].str;
398
key.type = HASH_KEY_ULONG;
399
key.ul = test[i].val;
402
if ((status = hash_lookup(table, &key, &value)) != HASH_SUCCESS) {
403
fprintf(stderr, "Error: failed delete lookup for value %ld at index %ld at line %d (%s)\n",
404
test[i].val, i, __LINE__, error_string(status));
408
if ((status = hash_delete(table, &key)) != HASH_SUCCESS) {
409
fprintf(stderr, "Error: %ld not in table when deleting, i = %lu at line %d (%s)\n",
410
test[i].val, i, __LINE__, error_string(status));
414
if (hash_lookup(table, &key, &value) != HASH_ERROR_KEY_NOT_FOUND) {
415
fprintf(stderr, "Error: found in table after deletion, value = %ld at index %ld at line %d\n",
416
test[i].val, i, __LINE__);
419
/* See if we can find all remaining keys */
420
for (k = i + 1; k < max_test; k++) {
421
if (test[k].val & 1) {
422
key.type = HASH_KEY_STRING;
423
key.str = test[k].str;
425
key.type = HASH_KEY_ULONG;
426
key.ul = test[k].val;
428
if ((status = hash_lookup(table, &key, &value)) != HASH_SUCCESS) {
429
fprintf(stderr, "Error: failed second lookup for value %ld, i = %lu k = %lu at line %d (%s)\n",
430
test[k].val, i, k, __LINE__, error_string(status));
435
if (strcmp((char *)value.ptr, test[k].str) != 0) {
436
fprintf(stderr, "Error: corrupt ptr data for %lu at line %d\n", k, __LINE__);
440
case HASH_VALUE_LONG:
441
if (value.l != test[k].val) {
442
fprintf(stderr, "Error: corrupt long data for %lu at line %d\n", k, __LINE__);
447
fprintf(stderr, "Error: unknown value type (%d) for %lu\n", value.type, k);
454
if (verbose) printf("\n");
456
#ifdef HASH_STATISTICS
458
hash_statistics_t stats;
460
if ((status = hash_get_statistics(table, &stats)) != HASH_SUCCESS) {
461
fprintf(stderr, "Error: could not get statistics at line %d (%s)\n",
462
__LINE__, error_string(status));
466
printf("Statistics: Accesses = %ld, Collisions = %ld, Collision Rate = %.2f, Expansions = %ld, Contractions = %ld\n",
467
stats.hash_accesses, stats.hash_collisions,
468
((float)stats.hash_collisions / (float)stats.hash_accesses),
469
stats.table_expansions, stats.table_contractions);
473
if ((status = hash_destroy(table)) != HASH_SUCCESS) {
474
fprintf(stderr, "table destruction failed at line %d (%s)\n",
475
__LINE__, error_string(status));
479
for (i = 0; i < max_test; i++) {
480
if (test[i].val & 1) {
488
printf("Successfully tested %lu values\n", max_test);