struct tree_node {
    struct tree_node* zero;
    struct tree_node* one;
    unsigned char* value;
};

struct tree_value {
    int mask;
    int addr[];
};

struct tree_head {
    int reclen;
    struct tree_node* root;
};

int bitVals[] = {
    0x80000000, 0x40000000, 0x20000000, 0x10000000,
    0x8000000, 0x4000000, 0x2000000, 0x1000000,
    0x800000, 0x400000, 0x200000, 0x100000,
    0x80000, 0x40000, 0x20000, 0x10000,
    0x8000, 0x4000, 0x2000, 0x1000,
    0x800, 0x400, 0x200, 0x100,
    0x80, 0x40, 0x20, 0x10,
    0x8, 0x4, 0x2, 0x1
};


void tree_init(struct tree_head *tab, int reclen) {
    tab->reclen = reclen;
    tab->root = malloc(sizeof(struct tree_node));
    if (tab->root == NULL) err("error allocating memory");
    memset(tab->root, 0, sizeof(struct tree_node));
}

void tree_deinit(struct tree_head *tab) {
    tab->reclen = 0;
    free(tab->root);
    tab->root = NULL;
}

#define tree_bit(p) (val->addr[p / 32] & bitVals[p % 32])

void* tree_lpm(struct tree_head *tab, void *ntry) {
    struct tree_node* cur = tab->root;
    struct tree_value* val = ntry;
    int vlmsk = val->mask;
    void* lst = NULL;
    for (int p = 0;; p++) {
        if (cur->value != NULL) lst = cur->value;
        if (p >= vlmsk) return lst;
        if (tree_bit(p) != 0) {
            cur = cur->one;
        } else {
            cur = cur->zero;
        }
        if (cur == NULL) return lst;
    }
}

void tree_add(struct tree_head *tab, void *ntry) {
    struct tree_node* cur = tab->root;
    struct tree_value* val = ntry;
    int vlmsk = val->mask;
    for (int p = 0;; p++) {
        if (p >= vlmsk) {
            if (cur->value != NULL) {
                memcpy(cur->value, ntry, tab->reclen);
                return;
            }
            void* nxt = malloc(tab->reclen);
            if (nxt == NULL) err("error allocating memory");
            memcpy(nxt, ntry, tab->reclen);
            cur->value = nxt;
            return;
        }
        if (tree_bit(p) != 0) {
            if (cur->one != NULL) {
                cur = cur->one;
                continue;
            }
            struct tree_node* nxt = malloc(sizeof(struct tree_node));
            if (nxt == NULL) err("error allocating memory");
            memset(nxt, 0, sizeof(struct tree_node));
            cur->one = nxt;
            cur = nxt;
        } else {
            if (cur->zero != NULL) {
                cur = cur->zero;
                continue;
            }
            struct tree_node* nxt = malloc(sizeof(struct tree_node));
            if (nxt == NULL) err("error allocating memory");
            memset(nxt, 0, sizeof(struct tree_node));
            cur->zero = nxt;
            cur = nxt;
        }
    }
}

void tree_del(struct tree_head *tab, void *ntry) {
    struct tree_node* cur = tab->root;
    struct tree_value* val = ntry;
    int vlmsk = val->mask;
    for (int p = 0;; p++) {
        if (p >= vlmsk) {
            void* old = cur->value;
            if (old == NULL) return;
            cur->value = NULL;
            free(old);
            return;
        }
        if (tree_bit(p) != 0) {
            cur = cur->one;
        } else {
            cur = cur->zero;
        }
        if (cur == NULL) return;
    }
}

void tree_walkNode(struct tree_node *cur, void doer(void *, int, void *), int fixed, void* param) {
    if (cur == NULL) return;
    tree_walkNode(cur->zero, doer, fixed, param);
    tree_walkNode(cur->one, doer, fixed, param);
    if (cur->value == NULL) return;
    doer(cur->value, fixed, param);
}

void tree_walk(struct tree_head *tab, void doer(void *, int, void *), int fixed, void* param) {
    struct tree_node* cur = tab->root;
    tree_walkNode(cur, doer, fixed, param);
}
