/* stringmap_insert: * Insert into S an item having key k and value d. Returns a pointer to * the existing item value, or NULL if a new item was created. */ item *stringmap_insert(stringmap S, const char *k, const item d) { if (!S) return NULL; if (S->key == NULL) { S->key = xstrdup(k); S->d = d; return NULL; } else { stringmap S2; for (S2 = S;;) { int i = strcmp(k, S2->key); if (i == 0) { return &(S2->d); } else if (i < 0) { if (S2->l) S2 = S2->l; else { if (!(S2->l = stringmap_new())) return NULL; S2->l->key = xstrdup(k); S2->l->d = d; return NULL; } } else if (i > 0) { if (S2->g) S2 = S2->g; else { if (!(S2->g = stringmap_new())) return NULL; S2->g->key = xstrdup(k); S2->g->d = d; return NULL; } } } } }
static void test_trivial(void) { stringmap(int) map = stringmap_new(NULL); ok1(stringmap_lookup(map, "") == NULL); *stringmap_enter(map, "") = -1; ok1(stringmap_lookup(map, "0") == NULL); *stringmap_enter(map, "0") = 0; ok1(stringmap_lookup(map, "one") == NULL); *stringmap_enter(map, "one") = 1; ok1(stringmap_lookup(map, "two") == NULL); *stringmap_enter(map, "two") = 2; ok1(stringmap_lookup(map, "three") == NULL); *stringmap_enter(map, "three") = 3; ok1(stringmap_lookup(map, "four") == NULL); *stringmap_enter(map, "four") = 4; ok1(*stringmap_lookup(map, "three") == 3); ok1(*stringmap_lookup(map, "one") == 1); ok1(*stringmap_lookup(map, "four") == 4); ok1(*stringmap_lookup(map, "two") == 2); ok1(*stringmap_lookup(map, "") == -1); ok1(*stringmap_lookup(map, "0") == 0); ok1(map.t.count == 6); stringmap_free(map); }
int config_init() { config = stringmap_new(); return config != NULL; }
static int test_stringmap(size_t count, FILE *out) { stringmap(char*) map = stringmap_new(NULL); struct block_pool *bp = block_pool_new(NULL); struct test_entry *entries = block_pool_alloc(bp, sizeof(*entries) * count); struct test_entry *i, *e = entries+count, *o; char *value_base = block_pool_alloc(bp, count), *value = value_base; size_t unique_count = 0; //we use value to track whether an entry has been added or not memset(value, 0, count); msg("Generating %zu test entries...", count); for (i=entries; i<e; value++) { size_t len; char *str = random_string(bp, &len); size_t same_count = (random()%5 ? random()%3 : random()%10) + 1; for (;same_count-- && i<e; i++) { i->str = str; i->len = len; i->value = value; } } cull_duplicates(entries, &count); e = entries+count; scramble(entries, count, sizeof(*entries)); msg("Inserting/looking up %zu entries...", count); for (i=entries, o=entries; i<e; i++) { char **node; debug("Looking up %s", i->str); node = stringmap_lookup_n(map, i->str, i->len); if (!node) { if (*i->value) err("Previously inserted entry not found"); debug("Not found; entering %s", i->str); node = stringmap_enter_n(map, i->str, i->len); if (!node || tecmp(i, (void*)map.last)) err("Node not properly entered"); if (map.last->str[map.last->len]) err("Entered string not zero-terminated"); *node = i->value; *i->value = 1; //mark that the entry is entered //write this unique entry to the entry list to traverse later *o++ = *i; } else { if (tecmp(i, (void*)map.last)) err("lookup returned incorrect string"); if (map.last->str[map.last->len]) err("Looked-up string not zero-terminated"); if (i->value != *node) err("lookup returned incorrect value"); if (!*i->value) err("lookup returned bogus value"); } } unique_count = o-entries; if (map.t.count != unique_count) err("Map has incorrect count"); qsort(entries, unique_count, sizeof(*entries), by_str); msg("Traversing forward through %zu items", unique_count); if (!test_traverse(&map.t, entries, unique_count, out)) err("Traversal does not produce the strings in order"); printf("stringmap test passed after %zu inserts, %zu lookups (%zu total operations)\n", unique_count, (i-entries)-unique_count, i-entries); block_pool_free(bp); stringmap_free(map); return 1; fail: printf("stringmap test failed after %zu inserts, %zu lookups (%zu total operations)\n", unique_count, (i-entries)-unique_count, i-entries); block_pool_free(bp); stringmap_free(map); return 0; }