const char* hattrie_iter_key(hattrie_iter_t* i, size_t* len) { if (hattrie_iter_finished(i)) return NULL; uint16_t sublen; const char* subkey; if (i->has_nil_key) { subkey = NULL; sublen = 0; } else subkey = hhash_iter_key(i->i, &sublen); if (i->keysize < i->level + sublen + 1) { while (i->keysize < i->level + sublen + 1) i->keysize *= 2; i->key = realloc(i->key, i->keysize * sizeof(char)); } if (sublen > 0) { memcpy(i->key + i->level, subkey, sublen); } i->key[i->level + sublen] = '\0'; *len = i->level + sublen; return i->key; }
static void hashnode_split_reinsert(hattrie_t *T, node_ptr parent, node_ptr src) { value_t* u = NULL; const char* key = NULL; uint16_t len = 0; hhash_iter_t i; hhash_iter_begin(src.b, &i, false); while (!hhash_iter_finished(&i)) { key = hhash_iter_key(&i, &len); u = hhash_iter_val(&i); *find_below(T, parent, key, len) = *u; hhash_iter_next(&i); } hhash_free(src.b); }
int hattrie_split_mid(node_ptr node, unsigned *left_m, unsigned *right_m) { /* count the number of occourances of every leading character */ unsigned int cs[NODE_CHILDS]; // occurance count for leading chars memset(cs, 0, NODE_CHILDS * sizeof(unsigned int)); uint16_t len; const char* key; /*! \todo expensive, maybe some heuristics or precalc would be better */ hhash_iter_t i; hhash_iter_begin(node.b, &i, false); while (!hhash_iter_finished(&i)) { key = hhash_iter_key(&i, &len); assert(len > 0); cs[(unsigned char) key[0]] += 1; hhash_iter_next(&i); } /* choose a split point */ unsigned int all_m; unsigned char j = node.b->c0; all_m = node.b->weight; *left_m = cs[j]; *right_m = all_m - *left_m; int d; while (j + 1 < node.b->c1) { d = abs((int) (*left_m + cs[j + 1]) - (int) (*right_m - cs[j + 1])); if (d <= abs((int) (*left_m) - (int) (*right_m)) && *left_m + cs[j + 1] < all_m) { j += 1; *left_m += cs[j]; *right_m -= cs[j]; } else break; } return j; }
int main(int argc, char *argv[]) { plan(11); /* Create memory pool context. */ struct mempool *pool = mp_new(64 * 1024); knot_mm_t mm; mm.ctx = pool; mm.alloc = (knot_mm_alloc_t)mp_alloc; mm.free = NULL; /* Create hashtable */ int ret = KNOT_EOK; uint16_t len = 0; const char *key = "mykey", *cur = NULL, *prev = NULL; value_t val = (void*)0xdeadbeef, *rval = NULL; hhash_iter_t it; hhash_t *tbl = hhash_create_mm(ELEM_COUNT, &mm); ok(tbl != NULL, "hhash: create"); if (tbl == NULL) { return KNOT_ERROR; /* No point in testing further on. */ } /* Generate random keys. */ char *keys[ELEM_COUNT]; unsigned nfilled = 0; for (unsigned i = 0; i < ELEM_COUNT; ++i) { keys[i] = test_randstr_mm(&mm); } /* Insert single element. */ ret = hhash_insert(tbl, key, KEY_LEN(key), val); ok(ret == KNOT_EOK, "hhash: insert single element"); /* Retrieve nonexistent element. */ cur = "nokey"; rval = hhash_find(tbl, cur, KEY_LEN(cur)); ok(rval == NULL, "hhash: find non-existent element"); /* Retrieve single element. */ rval = hhash_find(tbl, key, KEY_LEN(key)); ok(rval != NULL, "hhash: find existing element"); /* Fill the table. */ for (unsigned i = 0; i < ELEM_COUNT; ++i) { ret = hhash_insert(tbl, keys[i], KEY_LEN(keys[i]), keys[i]); if (ret != KNOT_EOK) { nfilled = i; break; } } /* Check all keys integrity. */ unsigned nfound = 0; for (unsigned i = 0; i < nfilled; ++i) { rval = hhash_find(tbl, keys[i], KEY_LEN(keys[i])); if (!rval || memcmp(*rval, keys[i], KEY_LEN(keys[i])) != 0) { break; /* Mismatch */ } ++nfound; } is_int(nfilled, nfound, "hhash: found all inserted keys"); /* Test keys order index. */ hhash_build_index(tbl); hhash_iter_begin(tbl, &it, true); while (!hhash_iter_finished(&it)) { cur = hhash_iter_key(&it, &len); if (!str_check_sort(prev, cur)) { break; } prev = cur; int strl = strlen(cur); assert(strl + 1 == len); hhash_iter_next(&it); } ok(hhash_iter_finished(&it), "hhash: passed order index checks"); /* Retrieve all keys. */ nfound = 0; hhash_iter_begin(tbl, &it, false); while (!hhash_iter_finished(&it)) { cur = hhash_iter_key(&it, &len); if (hhash_find(tbl, cur, len) == NULL) { break; } else { ++nfound; } hhash_iter_next(&it); } ok(hhash_iter_finished(&it), "hhash: found all iterated keys"); is_int(tbl->weight, nfound, "hhash: all iterated keys found"); /* Test find less or equal. */ prev = "mykey0"; /* mykey should precede it */ hhash_find_leq(tbl, prev, KEY_LEN(prev), &rval); ok(rval && *rval == val, "hhash: find less or equal"); /* Delete key and retrieve it. */ ret = hhash_del(tbl, key, KEY_LEN(key)); ok(ret == KNOT_EOK, "hhash: remove key"); rval = hhash_find(tbl, key, KEY_LEN(key)); ok(rval == NULL, "hhash: find removed element"); /* Free all memory. */ mp_delete(mm.ctx); return KNOT_EOK; }