#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "radtree.h"
#include "util.h"
#include "region-allocator.h"
#include <stdio.h>
#include <ctype.h>
struct radtree* radix_tree_create(struct region* region)
{
struct radtree* rt = (struct radtree*)region_alloc(region, sizeof(*rt));
if(!rt) return NULL;
rt->region = region;
radix_tree_init(rt);
return rt;
}
void radix_tree_init(struct radtree* rt)
{
rt->root = NULL;
rt->count = 0;
}
static void radnode_del_postorder(struct region* region, struct radnode* n)
{
unsigned i;
if(!n) return;
for(i=0; i<n->len; i++) {
radnode_del_postorder(region, n->array[i].node);
region_recycle(region, n->array[i].str, n->array[i].len);
}
region_recycle(region, n->array, n->capacity*sizeof(struct radsel));
region_recycle(region, n, sizeof(*n));
}
void radix_tree_clear(struct radtree* rt)
{
radnode_del_postorder(rt->region, rt->root);
rt->root = NULL;
rt->count = 0;
}
void radix_tree_delete(struct radtree* rt)
{
if(!rt) return;
radix_tree_clear(rt);
region_recycle(rt->region, rt, sizeof(*rt));
}
static struct radnode*
radnode_last_in_subtree(struct radnode* n)
{
int idx;
for(idx=((int)n->len)-1; idx >= 0; idx--) {
if(n->array[idx].node) {
if(n->array[idx].node->len > 0) {
struct radnode* s = radnode_last_in_subtree(
n->array[idx].node);
if(s) return s;
}
if(n->array[idx].node->elem)
return n->array[idx].node;
}
}
return NULL;
}
static struct radnode*
radnode_last_in_subtree_incl_self(struct radnode* n)
{
struct radnode* s = radnode_last_in_subtree(n);
if(s) return s;
if(n->elem) return n;
return NULL;
}
static struct radnode*
radnode_first_in_subtree(struct radnode* n)
{
unsigned idx;
struct radnode* s;
for(idx=0; idx<n->len; idx++) {
if(n->array[idx].node) {
if(n->array[idx].node->elem)
return n->array[idx].node;
if((s=radnode_first_in_subtree(n->array[idx].node))!=0)
return s;
}
}
return NULL;
}
static struct radnode*
radnode_find_prev_from_idx(struct radnode* n, unsigned from)
{
unsigned idx = from;
while(idx > 0) {
idx --;
if(n->array[idx].node) {
struct radnode* s = radnode_last_in_subtree_incl_self(
n->array[idx].node);
if(s) return s;
}
}
return NULL;
}
static int radix_find_prefix_node(struct radtree* rt, uint8_t* k,
radstrlen_type len, struct radnode** result, radstrlen_type* respos)
{
struct radnode* n = rt->root;
radstrlen_type pos = 0;
uint8_t byte;
*respos = 0;
*result = n;
if(!n) return 0;
while(n) {
if(pos == len) {
return 1;
}
byte = k[pos];
if(byte < n->offset) {
return 1;
}
byte -= n->offset;
if(byte >= n->len) {
return 1;
}
pos++;
if(n->array[byte].len != 0) {
if(pos+n->array[byte].len > len) {
return 1;
}
if(memcmp(&k[pos], n->array[byte].str,
n->array[byte].len) != 0) {
return 1;
}
pos += n->array[byte].len;
}
n = n->array[byte].node;
if(!n) return 1;
*respos = pos;
*result = n;
}
return 1;
}
static int
radnode_array_grow(struct region* region, struct radnode* n, unsigned want)
{
unsigned ns = ((unsigned)n->capacity)*2;
struct radsel* a;
assert(want <= 256);
if(want > ns)
ns = want;
if(ns > 256) ns = 256;
a = (struct radsel*)region_alloc_array(region, ns, sizeof(struct radsel));
if(!a) return 0;
assert(n->len <= n->capacity);
assert(n->capacity < ns);
memcpy(&a[0], &n->array[0], n->len*sizeof(struct radsel));
region_recycle(region, n->array, n->capacity*sizeof(struct radsel));
n->array = a;
n->capacity = ns;
return 1;
}
static int
radnode_array_space(struct region* region, struct radnode* n, uint8_t byte)
{
if(!n->array || n->capacity == 0) {
n->array = (struct radsel*)region_alloc(region,
sizeof(struct radsel));
if(!n->array) return 0;
memset(&n->array[0], 0, sizeof(struct radsel));
n->len = 1;
n->capacity = 1;
n->offset = byte;
} else if(n->len == 0 && n->capacity != 0) {
n->len = 1;
n->offset = byte;
memset(&n->array[0], 0, sizeof(struct radsel));
} else if(byte < n->offset) {
unsigned idx;
unsigned need = n->offset-byte;
if(n->len+need > n->capacity) {
if(!radnode_array_grow(region, n, n->len+need))
return 0;
}
memmove(&n->array[need], &n->array[0],
n->len*sizeof(struct radsel));
for(idx = 0; idx < n->len; idx++) {
if(n->array[idx+need].node)
n->array[idx+need].node->pidx = idx+need;
}
memset(&n->array[0], 0, need*sizeof(struct radsel));
n->len += need;
n->offset = byte;
} else if(byte-n->offset >= n->len) {
unsigned need = (byte-n->offset) - n->len + 1;
if(n->len + need > n->capacity) {
if(!radnode_array_grow(region, n, n->len+need))
return 0;
}
memset(&n->array[n->len], 0, need*sizeof(struct radsel));
n->len += need;
}
return 1;
}
static int
radsel_str_create(struct region* region, struct radsel* r, uint8_t* k,
radstrlen_type pos, radstrlen_type len)
{
r->str = (uint8_t*)region_alloc(region, sizeof(uint8_t)*(len-pos));
if(!r->str)
return 0;
memmove(r->str, k+pos, len-pos);
r->len = len-pos;
return 1;
}
static int
bstr_is_prefix(uint8_t* p, radstrlen_type plen, uint8_t* x,
radstrlen_type xlen)
{
if(plen == 0)
return 1;
if(plen > xlen)
return 0;
return (memcmp(p, x, plen) == 0);
}
static radstrlen_type
bstr_common(uint8_t* x, radstrlen_type xlen, uint8_t* y, radstrlen_type ylen)
{
unsigned i, max = ((xlen<ylen)?xlen:ylen);
for(i=0; i<max; i++) {
if(x[i] != y[i])
return i;
}
return max;
}
int
bstr_is_prefix_ext(uint8_t* p, radstrlen_type plen, uint8_t* x,
radstrlen_type xlen)
{
return bstr_is_prefix(p, plen, x, xlen);
}
radstrlen_type
bstr_common_ext(uint8_t* x, radstrlen_type xlen, uint8_t* y,
radstrlen_type ylen)
{
return bstr_common(x, xlen, y, ylen);
}
static int
radsel_prefix_remainder(struct region* region, radstrlen_type plen,
uint8_t* l, radstrlen_type llen,
uint8_t** s, radstrlen_type* slen)
{
*slen = llen - plen;
*s = (uint8_t*)region_alloc(region, (*slen)*sizeof(uint8_t));
if(!*s)
return 0;
memmove(*s, l+plen, llen-plen);
return 1;
}
static int
radsel_split(struct region* region, struct radsel* r, uint8_t* k,
radstrlen_type pos, radstrlen_type len, struct radnode* add)
{
uint8_t* addstr = k+pos;
radstrlen_type addlen = len-pos;
if(bstr_is_prefix(addstr, addlen, r->str, r->len)) {
uint8_t* split_str=NULL, *dupstr=NULL;
radstrlen_type split_len=0;
assert(addlen != r->len);
assert(addlen < r->len);
if(r->len-addlen > 1) {
if(!radsel_prefix_remainder(region, addlen+1, r->str,
r->len, &split_str, &split_len))
return 0;
}
if(addlen != 0) {
dupstr = (uint8_t*)region_alloc(region,
addlen*sizeof(uint8_t));
if(!dupstr) {
region_recycle(region, split_str, split_len);
return 0;
}
memcpy(dupstr, addstr, addlen);
}
if(!radnode_array_space(region, add, r->str[addlen])) {
region_recycle(region, split_str, split_len);
region_recycle(region, dupstr, addlen);
return 0;
}
add->parent = r->node->parent;
add->pidx = r->node->pidx;
add->array[0].node = r->node;
add->array[0].str = split_str;
add->array[0].len = split_len;
r->node->parent = add;
r->node->pidx = 0;
r->node = add;
region_recycle(region, r->str, r->len);
r->str = dupstr;
r->len = addlen;
} else if(bstr_is_prefix(r->str, r->len, addstr, addlen)) {
uint8_t* split_str = NULL;
radstrlen_type split_len = 0;
assert(addlen != r->len);
assert(r->len < addlen);
if(addlen-r->len > 1) {
if(!radsel_prefix_remainder(region, r->len+1, addstr,
addlen, &split_str, &split_len))
return 0;
}
if(!radnode_array_space(region, r->node, addstr[r->len])) {
region_recycle(region, split_str, split_len);
return 0;
}
add->parent = r->node;
add->pidx = addstr[r->len] - r->node->offset;
r->node->array[add->pidx].node = add;
r->node->array[add->pidx].str = split_str;
r->node->array[add->pidx].len = split_len;
} else {
struct radnode* com;
uint8_t* common_str=NULL, *s1_str=NULL, *s2_str=NULL;
radstrlen_type common_len, s1_len=0, s2_len=0;
common_len = bstr_common(r->str, r->len, addstr, addlen);
assert(common_len < r->len);
assert(common_len < addlen);
com = (struct radnode*)region_alloc_zero(region, sizeof(*com));
if(!com) return 0;
if(r->len-common_len > 1) {
if(!radsel_prefix_remainder(region, common_len+1,
r->str, r->len, &s1_str, &s1_len)) {
region_recycle(region, com, sizeof(*com));
return 0;
}
}
if(addlen-common_len > 1) {
if(!radsel_prefix_remainder(region, common_len+1,
addstr, addlen, &s2_str, &s2_len)) {
region_recycle(region, com, sizeof(*com));
region_recycle(region, s1_str, s1_len);
return 0;
}
}
if(common_len > 0) {
common_str = (uint8_t*)region_alloc(region,
common_len*sizeof(uint8_t));
if(!common_str) {
region_recycle(region, com, sizeof(*com));
region_recycle(region, s1_str, s1_len);
region_recycle(region, s2_str, s2_len);
return 0;
}
memcpy(common_str, addstr, common_len);
}
if(!radnode_array_space(region, com, r->str[common_len]) ||
!radnode_array_space(region, com, addstr[common_len])) {
region_recycle(region, com->array, com->capacity*sizeof(struct radsel));
region_recycle(region, com, sizeof(*com));
region_recycle(region, common_str, common_len);
region_recycle(region, s1_str, s1_len);
region_recycle(region, s2_str, s2_len);
return 0;
}
com->parent = r->node->parent;
com->pidx = r->node->pidx;
r->node->parent = com;
r->node->pidx = r->str[common_len]-com->offset;
add->parent = com;
add->pidx = addstr[common_len]-com->offset;
com->array[r->node->pidx].node = r->node;
com->array[r->node->pidx].str = s1_str;
com->array[r->node->pidx].len = s1_len;
com->array[add->pidx].node = add;
com->array[add->pidx].str = s2_str;
com->array[add->pidx].len = s2_len;
region_recycle(region, r->str, r->len);
r->str = common_str;
r->len = common_len;
r->node = com;
}
return 1;
}
struct radnode* radix_insert(struct radtree* rt, uint8_t* k,
radstrlen_type len, void* elem)
{
struct radnode* n;
radstrlen_type pos = 0;
struct radnode* add = (struct radnode*)region_alloc_zero(rt->region,
sizeof(*add));
if(!add) return NULL;
add->elem = elem;
if(!radix_find_prefix_node(rt, k, len, &n, &pos)) {
assert(rt->root == NULL);
if(len == 0) {
rt->root = add;
} else {
n = (struct radnode*)region_alloc_zero(rt->region,
sizeof(*n));
if(!n) {
region_recycle(rt->region, add, sizeof(*add));
return NULL;
}
if(!radnode_array_space(rt->region, n, k[0])) {
region_recycle(rt->region, n->array,
n->capacity*sizeof(struct radsel));
region_recycle(rt->region, n, sizeof(*n));
region_recycle(rt->region, add, sizeof(*add));
return NULL;
}
add->parent = n;
add->pidx = 0;
n->array[0].node = add;
if(len > 1) {
if(!radsel_prefix_remainder(rt->region, 1, k, len,
&n->array[0].str, &n->array[0].len)) {
region_recycle(rt->region, n->array,
n->capacity*sizeof(struct radsel));
region_recycle(rt->region, n, sizeof(*n));
region_recycle(rt->region, add, sizeof(*add));
return NULL;
}
}
rt->root = n;
}
} else if(pos == len) {
if(n->elem) {
region_recycle(rt->region, add, sizeof(*add));
return NULL;
}
n->elem = elem;
region_recycle(rt->region, add, sizeof(*add));
add = n;
} else {
uint8_t byte;
assert(pos < len);
byte = k[pos];
if(byte < n->offset || byte-n->offset >= n->len) {
if(!radnode_array_space(rt->region, n, byte)) {
region_recycle(rt->region, add, sizeof(*add));
return NULL;
}
assert(byte>=n->offset && byte-n->offset<n->len);
byte -= n->offset;
if(pos+1 < len) {
if(!radsel_str_create(rt->region, &n->array[byte],
k, pos+1, len)) {
region_recycle(rt->region, add, sizeof(*add));
return NULL;
}
}
add->parent = n;
add->pidx = byte;
n->array[byte].node = add;
} else if(n->array[byte-n->offset].node == NULL) {
byte -= n->offset;
if(pos+1 < len) {
if(!radsel_str_create(rt->region, &n->array[byte],
k, pos+1, len)) {
region_recycle(rt->region, add, sizeof(*add));
return NULL;
}
}
add->parent = n;
add->pidx = byte;
n->array[byte].node = add;
} else {
if(!radsel_split(rt->region, &n->array[byte-n->offset],
k, pos+1, len, add)) {
region_recycle(rt->region, add, sizeof(*add));
return NULL;
}
}
}
rt->count ++;
return add;
}
static void radnode_delete(struct region* region, struct radnode* n)
{
unsigned i;
if(!n) return;
for(i=0; i<n->len; i++) {
region_recycle(region, n->array[i].str, n->array[i].len);
}
region_recycle(region, n->array, n->capacity*sizeof(struct radsel));
region_recycle(region, n, sizeof(*n));
}
static int
radnode_cleanup_onechild(struct region* region, struct radnode* n,
struct radnode* par)
{
uint8_t* join;
radstrlen_type joinlen;
uint8_t pidx = n->pidx;
struct radnode* child = n->array[0].node;
assert(pidx < par->len);
joinlen = par->array[pidx].len + n->array[0].len + 1;
join = (uint8_t*)region_alloc(region, joinlen*sizeof(uint8_t));
if(!join) {
return 0;
}
if(par->array[pidx].str)
memcpy(join, par->array[pidx].str, par->array[pidx].len);
join[par->array[pidx].len] = child->pidx + n->offset;
if(n->array[0].str)
memmove(join+par->array[pidx].len+1, n->array[0].str, n->array[0].len);
region_recycle(region, par->array[pidx].str, par->array[pidx].len);
par->array[pidx].str = join;
par->array[pidx].len = joinlen;
par->array[pidx].node = child;
child->parent = par;
child->pidx = pidx;
radnode_delete(region, n);
return 1;
}
static void
radnode_array_clean_all(struct region* region, struct radnode* n)
{
n->offset = 0;
n->len = 0;
region_recycle(region, n->array, n->capacity*sizeof(struct radsel));
n->array = NULL;
n->capacity = 0;
}
static void
radnode_array_reduce_if_needed(struct region* region, struct radnode* n)
{
if(n->len <= n->capacity/2 && n->len != n->capacity) {
struct radsel* a = (struct radsel*)region_alloc_array(region,
sizeof(*a), n->len);
if(!a) return;
memcpy(a, n->array, sizeof(*a)*n->len);
region_recycle(region, n->array, n->capacity*sizeof(*a));
n->array = a;
n->capacity = n->len;
}
}
static void
radnode_array_clean_front(struct region* region, struct radnode* n)
{
unsigned idx, shuf = 0;
while(shuf < n->len && n->array[shuf].node == NULL)
shuf++;
if(shuf == 0)
return;
if(shuf == n->len) {
radnode_array_clean_all(region, n);
return;
}
assert(shuf < n->len);
assert((int)shuf <= 255-(int)n->offset);
memmove(&n->array[0], &n->array[shuf],
(n->len - shuf)*sizeof(struct radsel));
n->offset += shuf;
n->len -= shuf;
for(idx=0; idx<n->len; idx++)
if(n->array[idx].node)
n->array[idx].node->pidx = idx;
radnode_array_reduce_if_needed(region, n);
}
static void
radnode_array_clean_end(struct region* region, struct radnode* n)
{
unsigned shuf = 0;
while(shuf < n->len && n->array[n->len-1-shuf].node == NULL)
shuf++;
if(shuf == 0)
return;
if(shuf == n->len) {
radnode_array_clean_all(region, n);
return;
}
assert(shuf < n->len);
n->len -= shuf;
radnode_array_reduce_if_needed(region, n);
}
static void
radnode_cleanup_leaf(struct region* region, struct radnode* n,
struct radnode* par)
{
uint8_t pidx;
pidx = n->pidx;
radnode_delete(region, n);
assert(pidx < par->len);
region_recycle(region, par->array[pidx].str, par->array[pidx].len);
par->array[pidx].str = NULL;
par->array[pidx].len = 0;
par->array[pidx].node = NULL;
if(par->len == 1) {
radnode_array_clean_all(region, par);
} else if(pidx == 0) {
radnode_array_clean_front(region, par);
} else if(pidx == par->len-1) {
radnode_array_clean_end(region, par);
}
}
static int
radnode_cleanup(struct radtree* rt, struct radnode* n)
{
while(n) {
if(n->elem) {
return 1;
} else if(n->len == 1 && n->parent) {
return radnode_cleanup_onechild(rt->region, n, n->parent);
} else if(n->len == 0) {
struct radnode* par = n->parent;
if(!par) {
radnode_delete(rt->region, n);
rt->root = NULL;
return 1;
}
radnode_cleanup_leaf(rt->region, n, par);
n = par;
} else {
return 1;
}
}
return 1;
}
void radix_delete(struct radtree* rt, struct radnode* n)
{
if(!n) return;
n->elem = NULL;
rt->count --;
if(!radnode_cleanup(rt, n)) {
}
}
struct radnode* radix_search(struct radtree* rt, uint8_t* k,
radstrlen_type len)
{
struct radnode* n = rt->root;
radstrlen_type pos = 0;
uint8_t byte;
while(n) {
if(pos == len)
return n->elem?n:NULL;
byte = k[pos];
if(byte < n->offset)
return NULL;
byte -= n->offset;
if(byte >= n->len)
return NULL;
pos++;
if(n->array[byte].len != 0) {
if(pos+n->array[byte].len > len)
return NULL;
if(memcmp(&k[pos], n->array[byte].str,
n->array[byte].len) != 0)
return NULL;
pos += n->array[byte].len;
}
n = n->array[byte].node;
}
return NULL;
}
static int ret_self_or_prev(struct radnode* n, struct radnode** result)
{
if(n->elem)
*result = n;
else *result = radix_prev(n);
return 0;
}
int radix_find_less_equal(struct radtree* rt, uint8_t* k, radstrlen_type len,
struct radnode** result)
{
struct radnode* n = rt->root;
radstrlen_type pos = 0;
uint8_t byte;
int r;
if(!n) {
*result = NULL;
return 0;
}
while(pos < len) {
byte = k[pos];
if(byte < n->offset) {
return ret_self_or_prev(n, result);
}
byte -= n->offset;
if(byte >= n->len) {
if((*result=radnode_last_in_subtree_incl_self(n))==0)
*result = radix_prev(n);
return 0;
}
pos++;
if(!n->array[byte].node) {
*result = radnode_find_prev_from_idx(n, byte);
if(*result)
return 0;
return ret_self_or_prev(n, result);
}
if(n->array[byte].len != 0) {
if(pos+n->array[byte].len > len) {
if( (memcmp(&k[pos], n->array[byte].str,
len-pos)) <= 0) {
*result = radix_prev(n->array[byte].node);
} else {
*result=radnode_last_in_subtree_incl_self(n->array[byte].node);
if(!*result)
*result = radix_prev(n->array[byte].node);
}
return 0;
}
if( (r=memcmp(&k[pos], n->array[byte].str,
n->array[byte].len)) < 0) {
*result = radix_prev(n->array[byte].node);
return 0;
} else if(r > 0) {
*result=radnode_last_in_subtree_incl_self(n->array[byte].node);
if(!*result) *result = radix_prev(n->array[byte].node);
return 0;
}
pos += n->array[byte].len;
}
n = n->array[byte].node;
}
if(n->elem) {
*result = n;
return 1;
}
*result = radix_prev(n);
return 0;
}
struct radnode* radix_first(struct radtree* rt)
{
struct radnode* n;
if(!rt || !rt->root) return NULL;
n = rt->root;
if(n->elem) return n;
return radix_next(n);
}
struct radnode* radix_last(struct radtree* rt)
{
if(!rt || !rt->root) return NULL;
return radnode_last_in_subtree_incl_self(rt->root);
}
struct radnode* radix_next(struct radnode* n)
{
if(!n) return NULL;
if(n->len) {
struct radnode* s = radnode_first_in_subtree(n);
if(s) return s;
}
while(n->parent) {
unsigned idx = n->pidx;
n = n->parent;
idx++;
for(; idx < n->len; idx++) {
if(n->array[idx].node) {
struct radnode* s;
if(n->array[idx].node->elem)
return n->array[idx].node;
s = radnode_first_in_subtree(
n->array[idx].node);
if(s) return s;
}
}
}
return NULL;
}
struct radnode* radix_prev(struct radnode* n)
{
if(!n) return NULL;
while(n->parent) {
uint8_t idx = n->pidx;
struct radnode* s;
n = n->parent;
assert(n->len > 0);
s = radnode_find_prev_from_idx(n, idx);
if(s) return s;
if(n->elem)
return n;
}
return NULL;
}
static uint8_t char_d2r(uint8_t c)
{
if(c < 'A') return c+1;
else if(c <= 'Z') return c-'A'+'a';
else return c;
}
static uint8_t char_r2d(uint8_t c)
{
assert(c != 0);
if(c <= 'A') return c-1;
else return c;
}
static void cpy_d2r(uint8_t* to, const uint8_t* from, int len)
{
int i;
for(i=0; i<len; i++)
to[i] = char_d2r(from[i]);
}
static void cpy_r2d(uint8_t* to, uint8_t* from, uint8_t len)
{
uint8_t i;
for(i=0; i<len; i++)
to[i] = char_r2d(from[i]);
}
void radname_d2r(uint8_t* k, radstrlen_type* len, const uint8_t* dname,
size_t dlen)
{
const uint8_t* labstart[130];
unsigned int lab = 0, kpos, dpos = 0;
assert(k && dname);
assert(dlen <= 256);
assert(*len >= dlen);
assert(dlen > 0);
if(dlen == 1) {
assert(dname[0] == 0);
*len = 0;
return;
}
do {
if((dname[dpos] & 0xc0)) {
*len = 0;
return;
}
labstart[lab++] = &dname[dpos];
if(dpos + dname[dpos] + 1 >= dlen) {
*len = 0;
return;
}
dpos += dname[dpos];
dpos ++;
} while(dname[dpos] != 0);
assert(lab > 0);
lab-=1;
kpos = *labstart[lab];
cpy_d2r(k, labstart[lab]+1, kpos);
while(lab) {
k[kpos++]=0;
lab--;
cpy_d2r(k+kpos, labstart[lab]+1, *labstart[lab]);
kpos += *labstart[lab];
}
assert(kpos == dlen-2);
*len = kpos;
}
void radname_r2d(uint8_t* k, radstrlen_type len, uint8_t* dname, size_t* dlen)
{
uint8_t* labstart[130];
uint8_t lablen[130];
unsigned int lab = 0, dpos, kpos = 0;
assert(k && dname);
assert((size_t)*dlen >= (size_t)len+2);
assert(len <= 256);
if(len == 0) {
assert(*dlen > 0);
dname[0]=0;
*dlen=1;
return;
}
while(kpos < len) {
lablen[lab]=0;
labstart[lab]=&k[kpos];
while(kpos < len && k[kpos] != 0) {
lablen[lab]++;
kpos++;
}
lab++;
if(kpos < len) {
assert(k[kpos] == 0);
kpos++;
}
}
dpos = 0;
while(lab) {
lab--;
dname[dpos++] = lablen[lab];
cpy_r2d(dname+dpos, labstart[lab], lablen[lab]);
dpos += lablen[lab];
}
dname[dpos++] = 0;
assert((int)dpos == (int)len+2);
assert(dname[dpos-1] == 0);
*dlen = dpos;
}
struct radnode*
radname_insert(struct radtree* rt, const uint8_t* d, size_t max, void* elem)
{
uint8_t radname[300];
radstrlen_type len = (radstrlen_type)sizeof(radname);
if(max > sizeof(radname))
return NULL;
radname_d2r(radname, &len, d, max);
return radix_insert(rt, radname, len, elem);
}
void
radname_delete(struct radtree* rt, const uint8_t* d, size_t max)
{
struct radnode* n = radname_search(rt, d, max);
if(n) radix_delete(rt, n);
}
struct radnode* radname_search(struct radtree* rt, const uint8_t* d,
size_t max)
{
const uint8_t* labstart[130];
unsigned int lab, dpos, lpos;
struct radnode* n = rt->root;
uint8_t byte;
radstrlen_type i;
uint8_t b;
if(max < 1)
return NULL;
if(d[0] == 0) {
if(!n) return NULL;
return n->elem?n:NULL;
}
lab = 0;
dpos = 0;
do {
if((d[dpos] & 0xc0))
return NULL;
labstart[lab++] = &d[dpos];
if(dpos + d[dpos] + 1 >= max)
return NULL;
dpos += d[dpos];
dpos ++;
} while(d[dpos] != 0);
lab-=1;
lpos = 0;
while(n) {
if(lpos < *labstart[lab])
byte = char_d2r(labstart[lab][++lpos]);
else {
if(lab == 0)
return n->elem?n:NULL;
lpos = 0;
lab--;
byte = 0;
}
if(byte < n->offset)
return NULL;
byte -= n->offset;
if(byte >= n->len)
return NULL;
if(n->array[byte].len != 0) {
for(i=0; i<n->array[byte].len; i++) {
if(lpos < *labstart[lab])
b = char_d2r(labstart[lab][++lpos]);
else {
if(lab == 0)
return NULL;
lpos = 0;
lab--;
b = 0;
}
if(n->array[byte].str[i] != b)
return NULL;
}
}
n = n->array[byte].node;
}
return NULL;
}
int radname_find_less_equal(struct radtree* rt, const uint8_t* d, size_t max,
struct radnode** result)
{
const uint8_t* labstart[130];
unsigned int lab, dpos, lpos;
struct radnode* n = rt->root;
uint8_t byte;
radstrlen_type i;
uint8_t b;
if(!n) {
*result = NULL;
return 0;
}
if(max < 1) {
*result = NULL;
return 0;
}
if(d[0] == 0) {
if(n->elem) {
*result = n;
return 1;
}
*result = NULL;
return 0;
}
lab = 0;
dpos = 0;
do {
if((d[dpos] & 0xc0)) {
*result = NULL;
return 0;
}
labstart[lab++] = &d[dpos];
if(dpos + d[dpos] + 1 >= max) {
*result = NULL;
return 0;
}
dpos += d[dpos];
dpos ++;
} while(d[dpos] != 0);
lab-=1;
lpos = 0;
while(1) {
if(lpos < *labstart[lab])
byte = char_d2r(labstart[lab][++lpos]);
else {
if(lab == 0) {
if(n->elem) {
*result = n;
return 1;
}
*result = radix_prev(n);
return 0;
}
lpos = 0;
lab--;
byte = 0;
}
if(byte < n->offset)
return ret_self_or_prev(n, result);
byte -= n->offset;
if(byte >= n->len) {
*result = radnode_last_in_subtree_incl_self(n);
if(!*result)
*result = radix_prev(n);
return 0;
}
if(!n->array[byte].node) {
*result = radnode_find_prev_from_idx(n, byte);
if(*result)
return 0;
return ret_self_or_prev(n, result);
}
if(n->array[byte].len != 0) {
for(i=0; i<n->array[byte].len; i++) {
if(lpos < *labstart[lab])
b = char_d2r(labstart[lab][++lpos]);
else {
if(lab == 0) {
*result =radix_prev(
n->array[byte].node);
return 0;
}
lpos = 0;
lab--;
b = 0;
}
if(b < n->array[byte].str[i]) {
*result =radix_prev(
n->array[byte].node);
return 0;
} else if(b > n->array[byte].str[i]) {
*result = radnode_last_in_subtree_incl_self(n->array[byte].node);
if(!*result)
*result = radix_prev(n->array[byte].node);
return 0;
}
}
}
n = n->array[byte].node;
}
return 0;
}