示例#1
0
void test_ahtable_find_prev()
{
    fprintf(stderr, "finding prev for %zu keys ... \n", k);
    ahtable_build_index(T);

    ahtable_iter_t i;
    ahtable_iter_begin(T, &i, true);

    value_t* u;
    const char *key = NULL;
    char *dkey = NULL;
    size_t len = 0;

    while (!ahtable_iter_finished(&i)) {
        u  = ahtable_iter_val(&i);
        key = ahtable_iter_key(&i, &len);
       
        /* increase key last byte by 1 and check result */
        dkey = realloc(dkey, len); memcpy(dkey, key, len);
        ++dkey[len-1];
        value_t *fp = NULL;
        int r = ahtable_find_leq(T, dkey, len, &fp);
        if (*fp != *u || r != -1) {
            fprintf(stderr, "[error] ahtable_find_leq should find %lu, "
                    "but found prev=%lu and return -1, returned %d\n",
                    *u, *fp, r);
            
        }
        ahtable_iter_next(&i);
    }

    ahtable_iter_free(&i);
    free(dkey);
    fprintf(stderr, "done.\n");
}
示例#2
0
static void hattrie_split_fill(node_ptr src, node_ptr left, node_ptr right, uint8_t split)
{
    /* right should be most of the time hybrid */

    /* keep or distribute keys to the new right node */
    value_t* u;
    const char* key;
    size_t len;
    ahtable_iter_t i;
    ahtable_iter_begin(src.b, &i, false);
    while (!ahtable_iter_finished(&i)) {
        key = ahtable_iter_key(&i, &len);
        u   = ahtable_iter_val(&i);
        assert(len > 0);

        /* first char > split_point, move to the right */
        if ((unsigned char) key[0] > split) {
            if (src.b != right.b) {
                /* insert to right (new bucket) */
                if (*right.flag & NODE_TYPE_PURE_BUCKET) {
                    ahtable_insert(right.b, key + 1, len - 1, *u);
                }
                else {
                    ahtable_insert(right.b, key, len, *u);
                }
                /* transferred to right (from reused) */
                if (src.b == left.b) {
                    ahtable_iter_del(&i);
                    continue;
                }
            }   /* keep the node in right */
        } else {
            if (src.b != left.b) {
                /* insert to left (new bucket) */
                if (*left.flag & NODE_TYPE_PURE_BUCKET) {
                    ahtable_insert(left.b, key + 1, len - 1, *u);
                }
                else {
                    ahtable_insert(left.b, key, len, *u);
                }
                /* transferred to left (from reused) */
                if (src.b == right.b) {
                    ahtable_iter_del(&i);
                    continue;
                }
            }   /* keep the node in left */
        }

        ahtable_iter_next(&i);
    }

    ahtable_iter_free(&i);
}
示例#3
0
void hattrie_walk (hattrie_t* T, const char* key, size_t len, void* user_data, hattrie_walk_cb cb) {
    unsigned char* k = (unsigned char*)key;
    node_ptr node = T->root;
    size_t i, j;
    ahtable_iter_t* it;

    /* go down until a bucket is reached */
    for (i = 0; i < len; i++, k++) {
        if (!(*node.flag & NODE_TYPE_TRIE))
            break;
        node = node.t->xs[*k];
        if (*node.flag & NODE_HAS_VAL) {
            if (hattrie_walk_stop == cb(key, i, &node.t->val, user_data))
                return;
        }
    }
    if (i == len)
        return;

    assert(i);
    if (*node.flag & NODE_TYPE_HYBRID_BUCKET) {
        i--;
        k--;
    } else {
        assert(*node.flag & NODE_TYPE_PURE_BUCKET);
    }

    /* dict order ensured short => long */
    it = ahtable_iter_begin(node.b, true);
    for(; !ahtable_iter_finished(it); ahtable_iter_next(it)) {
        size_t stored_len;
        unsigned char* stored_key = (unsigned char*)ahtable_iter_key(it, &stored_len);
        int matched = 1;
        if (stored_len + i > len) {
            continue;
        }
        for (j = 0; j < stored_len; j++) {
            if (stored_key[j] != k[j]) {
                matched = 0;
                break;
            }
        }
        if (matched) {
            value_t* val = ahtable_iter_val(it);
            if (hattrie_walk_stop == cb(key, i + stored_len, val, user_data)) {
                ahtable_iter_free(it);
                return;
            }
        }
    }
    ahtable_iter_free(it);
}
示例#4
0
void test_ahtable_sorted_iteration()
{
    fprintf(stderr, "iterating in order through %zu keys ... \n", k);

    ahtable_iter_t i;
    ahtable_iter_begin(T, &i, true);

    size_t count = 0;
    value_t* u;
    value_t  v;

    char* prev_key = malloc(m_high + 1);
    size_t prev_len = 0;

    const char *key = NULL;
    size_t len = 0;

    while (!ahtable_iter_finished(&i)) {
        memcpy(prev_key, key, len);
        prev_len = len;
        ++count;

        key = ahtable_iter_key(&i, &len);
        if (prev_key != NULL && cmpkey(prev_key, prev_len, key, len) > 0) {
            fprintf(stderr, "[error] iteration is not correctly ordered.\n");
        }

        u  = ahtable_iter_val(&i);
        v  = str_map_get(M, key, len);

        if (*u != v) {
            if (v == 0) {
                fprintf(stderr, "[error] incorrect iteration (%lu, %lu)\n", *u, v);
            }
            else {
                fprintf(stderr, "[error] incorrect iteration tally (%lu, %lu)\n", *u, v);
            }
        }

        // this way we will see an error if the same key is iterated through
        // twice
        str_map_set(M, key, len, 0);

        ahtable_iter_next(&i);
    }

    ahtable_iter_free(&i);
    free(prev_key);

    fprintf(stderr, "done.\n");
}
示例#5
0
void test_ahtable_iteration()
{
    fprintf(stderr, "iterating through %zu keys ... \n", k);

    ahtable_iter_t i;
    ahtable_iter_begin(T, &i, false);

    size_t count = 0;
    value_t* u;
    value_t  v;

    size_t len;
    const char* key;

    while (!ahtable_iter_finished(&i)) {
        ++count;

        key = ahtable_iter_key(&i, &len);
        u   = ahtable_iter_val(&i);
        v   = str_map_get(M, key, len);

        if (*u != v) {
            if (v == 0) {
                fprintf(stderr, "[error] incorrect iteration (%lu, %lu)\n", *u, v);
            }
            else {
                fprintf(stderr, "[error] incorrect iteration tally (%lu, %lu)\n", *u, v);
            }
        }

        // this way we will see an error if the same key is iterated through
        // twice
        str_map_set(M, key, len, 0);

        ahtable_iter_next(&i);
    }

    if (count != M->m) {
        fprintf(stderr, "[error] iterated through %zu element, expected %zu\n",
                count, M->m);
    }

    ahtable_iter_free(&i);

    fprintf(stderr, "done.\n");
}
示例#6
0
static bool hattrie_iter_prefix_not_match(hattrie_iter_t* i)
{
    if (hattrie_iter_finished(i)) {
        return false; // can not advance the iter
    }
    if (i->level >= i->prefix_len) {
        return memcmp(i->key, i->prefix, i->prefix_len);
    } else if (i->has_nil_key) {
        return true; // subkey too short
    }

    size_t sublen;
    const char* subkey;
    subkey = ahtable_iter_key(i->i, &sublen);
    if (i->level + sublen < i->prefix_len) {
        return true; // subkey too short
    }
    return memcmp(i->key, i->prefix, i->level) ||
           memcmp(subkey, i->prefix + i->level, (i->prefix_len - i->level));
}
示例#7
0
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));
    size_t len;
    const char* key;

    /*! \todo expensive, maybe some heuristics or precalc would be better */
    ahtable_iter_t i;
    ahtable_iter_begin(node.b, &i, false);
    while (!ahtable_iter_finished(&i)) {
        key = ahtable_iter_key(&i, &len);
        assert(len > 0);
        cs[(unsigned char) key[0]] += 1;
        ahtable_iter_next(&i);
    }
    ahtable_iter_free(&i);

    /* choose a split point */
    unsigned int all_m;
    unsigned char j = node.b->c0;
    all_m   = ahtable_size(node.b);
    *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(*left_m - *right_m) && *left_m + cs[j + 1] < all_m) {
            j += 1;
            *left_m  += cs[j];
            *right_m -= cs[j];
        }
        else break;
    }

    return j;
}
示例#8
0
const char* hattrie_iter_key(hattrie_iter_t* i, size_t* len)
{
    if (hattrie_iter_finished(i)) return NULL;

    size_t sublen;
    const char* subkey;

    if (i->has_nil_key) {
        subkey = NULL;
        sublen = 0;
    }
    else subkey = ahtable_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_or_die(i->key, i->keysize * sizeof(char));
    }

    memcpy(i->key + i->level, subkey, sublen);
    i->key[i->level + sublen] = '\0';

    *len = i->level + sublen;
    return i->key;
}
示例#9
0
/* Perform one split operation on the given node with the given parent.
 */
static void hattrie_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 = ahtable_tryget(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;
            ahtable_del(node.b, NULL, 0);
        }

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

        return;
    }

    /* This is a hybrid bucket. Perform a proper split. */

    /* 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));
    size_t len;
    const char* key;

    ahtable_iter_t* i = ahtable_iter_begin(node.b, false);
    while (!ahtable_iter_finished(i)) {
        key = ahtable_iter_key(i, &len);
        assert(len > 0);
        cs[(unsigned char) key[0]] += 1;
        ahtable_iter_next(i);
    }
    ahtable_iter_free(i);

    /* choose a split point */
    unsigned int left_m, right_m, all_m;
    unsigned char j = node.b->c0;
    all_m   = ahtable_size(node.b);
    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(left_m - right_m) && left_m + cs[j + 1] < all_m) {
            j += 1;
            left_m  += cs[j];
            right_m -= cs[j];
        }
        else break;
    }

    /* now split into two node cooresponding to ranges [0, j] and
     * [j + 1, NODE_MAXCHAR], respectively. */


    /* create new left and right nodes */

    /* TODO: Add a special case if either node is a hybrid bucket containing all
     * the keys. In such a case, do not build a new table, just use the old one.
     * */
    size_t num_slots;


    for (num_slots = ahtable_initial_size;
            (double) left_m > ahtable_max_load_factor * (double) num_slots;
            num_slots *= 2);

    node_ptr left, right;
    left.b  = ahtable_create_n(num_slots);
    left.b->c0   = node.b->c0;
    left.b->c1   = j;
    left.b->flag = left.b->c0 == left.b->c1 ?
                      NODE_TYPE_PURE_BUCKET : NODE_TYPE_HYBRID_BUCKET;


    for (num_slots = ahtable_initial_size;
            (double) right_m > ahtable_max_load_factor * (double) num_slots;
            num_slots *= 2);

    right.b = ahtable_create_n(num_slots);
    right.b->c0   = j + 1;
    right.b->c1   = node.b->c1;
    right.b->flag = right.b->c0 == right.b->c1 ?
                      NODE_TYPE_PURE_BUCKET : NODE_TYPE_HYBRID_BUCKET;


    /* update the parent's pointer */

    unsigned int c;
    for (c = node.b->c0; c <= j; ++c) parent.t->xs[c] = left;
    for (; c <= node.b->c1; ++c)      parent.t->xs[c] = right;



    /* distribute keys to the new left or right node */
    value_t* u;
    value_t* v;
    i = ahtable_iter_begin(node.b, false);
    while (!ahtable_iter_finished(i)) {
        key = ahtable_iter_key(i, &len);
        u   = ahtable_iter_val(i);
        assert(len > 0);

        /* left */
        if ((unsigned char) key[0] <= j) {
            if (*left.flag & NODE_TYPE_PURE_BUCKET) {
                v = ahtable_get(left.b, key + 1, len - 1);
            }
            else {
                v = ahtable_get(left.b, key, len);
            }
            *v = *u;
        }

        /* right */
        else {
            if (*right.flag & NODE_TYPE_PURE_BUCKET) {
                v = ahtable_get(right.b, key + 1, len - 1);
            }
            else {
                v = ahtable_get(right.b, key, len);
            }
            *v = *u;
        }

        ahtable_iter_next(i);
    }

    ahtable_iter_free(i);
    ahtable_free(node.b);
}