Пример #1
0
/* Perform one split operation on the given node with the given parent.
 */
static void node_split(hattrie_t* T, node_ptr parent, node_ptr node)
{
    /* only buckets may be split */
    assert(*node.flag & NODE_TYPE_PURE_BUCKET ||
           *node.flag & NODE_TYPE_HYBRID_BUCKET);

    assert(*parent.flag & NODE_TYPE_TRIE);

    if (*node.flag & NODE_TYPE_PURE_BUCKET) {
        /* turn the pure bucket into a hybrid bucket */
        parent.t->xs[node.b->c0].t = alloc_trie_node(T, node);

        /* if the bucket had an empty key, move it to the new trie node */
        value_t* val = hhash_find(node.b, NULL, 0);
        if (val) {
            parent.t->xs[node.b->c0].t->val     = *val;
            parent.t->xs[node.b->c0].t->flag |= NODE_HAS_VAL;
            *val = 0;
            hhash_del(node.b, NULL, 0);
        }

        node.b->c0   = 0x00;
        node.b->c1   = TRIE_MAXCHAR;
        node.b->flag = NODE_TYPE_HYBRID_BUCKET;

        return;
    }

    /* This is a hybrid bucket. Perform a proper split. */
    hashnode_split(T, parent, node);
}
Пример #2
0
int hattrie_find_leq (hattrie_t* T, const char* key, size_t len, value_t** dst)
{
    /* create node stack for traceback */
    size_t sp = 0;
    node_ptr bs[NODESTACK_INIT];  /* base stack (will be enough mostly) */
    node_ptr *ns = bs;            /* generic ptr, could point to new mem */
    ns[sp] = T->root;

    /* find node for given key */
    int ret = 1; /* no node on the left matches */
    node_ptr node = hattrie_find_ns(&ns, &sp, NODESTACK_INIT, &key, &len);
    if (node.flag == NULL) {
        *dst = hattrie_walk_left(ns, sp, key, hattrie_find_rightmost);
        if (ns != bs) free(ns);
        if (*dst) {
            return -1; /* found previous */
        }
        return 1; /* no previous key found */
    }

    /* assign value from trie or find in table */
    if (*node.flag & NODE_TYPE_TRIE) {
        *dst = &node.t->val;
        ret = 0;     /* found exact match */
    } else {
        *dst = hhash_find(node.b, key, len);
        if (*dst) {
            ret = 0; /* found exact match */
        } else {     /* look for previous in hashtable */
            ret = hhash_find_leq(node.b, key, len, dst);
        }
    }

    /* return if found equal or left in hashtable */
    if (*dst == 0) {
        /* we're retracing from pure bucket, pop the key */
        if (*node.flag & NODE_TYPE_PURE_BUCKET) {
            --key;
        }
        /* walk up the stack of visited nodes and find closest match on the left */
        *dst = hattrie_walk_left(ns, sp, key, hattrie_find_rightmost);
        if (*dst) {
            ret = -1; /* found previous */
        } else {
            ret = 1; /* no previous key found */
        }
    }

    if (ns != bs) free(ns);
    return ret;
}
Пример #3
0
value_t* hattrie_tryget(hattrie_t* T, const char* key, size_t len)
{
    /* find node for given key */
    node_ptr parent = T->root;
    node_ptr node = hattrie_find(&parent, &key, &len);
    if (node.flag == NULL) {
        return NULL;
    }

    /* if the trie node consumes value, use it */
    if (*node.flag & NODE_TYPE_TRIE) {
        return &node.t->val;
    }

    return hhash_find(node.b, key, len);
}
Пример #4
0
Файл: hhash.c Проект: idtek/knot
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;
}