#include <stdio.h>
#include "alloc.h"
#include "out.h"
#include "stats.h"
#include "lut.h"
#include "lut_impl.h"
#include "tree.h"
static struct stats *Addtotal;
static struct stats *Lookuptotal;
static struct stats *Freetotal;
void
lut_init(void)
{
Addtotal = stats_new_counter("lut.adds", "total adds", 1);
Lookuptotal = stats_new_counter("lut.lookup", "total lookups", 1);
Freetotal = stats_new_counter("lut.frees", "total frees", 1);
}
void
lut_fini(void)
{
stats_delete(Addtotal);
stats_delete(Lookuptotal);
stats_delete(Freetotal);
}
struct lut *
lut_add(struct lut *root, void *lhs, void *rhs, lut_cmp cmp_func)
{
int diff;
struct lut **tmp_hdl = &root, *parent = NULL, *tmp = root;
while (tmp) {
if (cmp_func)
diff = (*cmp_func)(tmp->lut_lhs, lhs);
else
diff = (const char *)lhs - (const char *)tmp->lut_lhs;
if (diff == 0) {
tmp->lut_rhs = rhs;
return (root);
} else if (diff > 0) {
tmp_hdl = &(tmp->lut_left);
parent = tmp;
tmp = tmp->lut_left;
} else {
tmp_hdl = &(tmp->lut_right);
parent = tmp;
tmp = tmp->lut_right;
}
}
*tmp_hdl = MALLOC(sizeof (*root));
(*tmp_hdl)->lut_lhs = lhs;
(*tmp_hdl)->lut_rhs = rhs;
(*tmp_hdl)->lut_parent = parent;
(*tmp_hdl)->lut_left = (*tmp_hdl)->lut_right = NULL;
stats_counter_bump(Addtotal);
return (root);
}
void *
lut_lookup(struct lut *root, void *lhs, lut_cmp cmp_func)
{
int diff;
stats_counter_bump(Lookuptotal);
while (root) {
if (cmp_func)
diff = (*cmp_func)(root->lut_lhs, lhs);
else
diff = (const char *)lhs - (const char *)root->lut_lhs;
if (diff == 0)
return (root->lut_rhs);
else if (diff > 0)
root = root->lut_left;
else
root = root->lut_right;
}
return (NULL);
}
void *
lut_lookup_lhs(struct lut *root, void *lhs, lut_cmp cmp_func)
{
int diff;
stats_counter_bump(Lookuptotal);
while (root) {
if (cmp_func)
diff = (*cmp_func)(root->lut_lhs, lhs);
else
diff = (const char *)lhs - (const char *)root->lut_lhs;
if (diff == 0)
return (root->lut_lhs);
else if (diff > 0)
root = root->lut_left;
else
root = root->lut_right;
}
return (NULL);
}
void
lut_walk(struct lut *root, lut_cb callback, void *arg)
{
struct lut *tmp = root;
struct lut *prev_child = NULL;
if (root == NULL)
return;
while (tmp->lut_left != NULL)
tmp = tmp->lut_left;
(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
for (;;) {
if (tmp->lut_right != NULL && tmp->lut_right != prev_child) {
tmp = tmp->lut_right;
while (tmp->lut_left != NULL)
tmp = tmp->lut_left;
(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
} else if (tmp->lut_parent != NULL) {
prev_child = tmp;
tmp = tmp->lut_parent;
if (tmp->lut_right != prev_child)
(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
} else
return;
}
}
void
lut_free(struct lut *root, lut_cb callback, void *arg)
{
struct lut *tmp = root;
struct lut *prev_child = NULL;
if (root == NULL)
return;
while (tmp->lut_left != NULL)
tmp = tmp->lut_left;
if (callback)
(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
for (;;) {
if (tmp->lut_right != NULL && tmp->lut_right != prev_child) {
tmp = tmp->lut_right;
while (tmp->lut_left != NULL)
tmp = tmp->lut_left;
if (callback)
(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
} else if (tmp->lut_parent != NULL) {
prev_child = tmp;
tmp = tmp->lut_parent;
FREE(prev_child);
if (tmp->lut_right != prev_child && callback)
(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
} else {
FREE(tmp);
return;
}
}
}