You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
4.5 KiB
C
228 lines
4.5 KiB
C
10 years ago
|
#include <stddef.h> /* size_t, uintptr_t */
|
||
|
#include <stdint.h> /* for uint8_t, uint32_t */
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "critbit.h"
|
||
|
|
||
|
typedef struct {
|
||
|
void* child[2];
|
||
|
uint32_t byte;
|
||
|
uint8_t otherbits;
|
||
|
} critbit0_node;
|
||
|
|
||
|
#if 0
|
||
|
typedef struct{
|
||
|
void* root;
|
||
|
} critbit0_tree;
|
||
|
#endif
|
||
|
|
||
|
int critbit0_contains(critbit0_tree* t,const char* u) {
|
||
|
const uint8_t* ubytes= (void*)u;
|
||
|
const size_t ulen= strlen(u);
|
||
|
uint8_t* p= t->root;
|
||
|
|
||
|
if (!p) return 0;
|
||
|
|
||
|
while ((uintptr_t)p & 1) {
|
||
|
critbit0_node* q = (void*)(p-1);
|
||
|
|
||
|
uint8_t c = 0;
|
||
|
if (q->byte<ulen)
|
||
|
c = ubytes[q->byte];
|
||
|
|
||
|
const int direction = (1+(q->otherbits|c))>>8;
|
||
|
|
||
|
p = q->child[direction];
|
||
|
}
|
||
|
|
||
|
return 0==strcmp(u,(const char*)p);
|
||
|
}
|
||
|
|
||
|
int critbit0_insert(critbit0_tree* t,const char* u) {
|
||
|
const uint8_t* const ubytes = (void*)u;
|
||
|
const size_t ulen = strlen(u);
|
||
|
uint8_t* p = t->root;
|
||
|
|
||
|
if (!p) {
|
||
|
char* x = malloc(ulen+1);
|
||
|
if (!x) return 0;
|
||
|
memcpy(x,u,ulen+1);
|
||
|
t->root= x;
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
while (1&(intptr_t)p) {
|
||
|
critbit0_node* q = (void*)(p-1);
|
||
|
|
||
|
uint8_t c = 0;
|
||
|
if (q->byte<ulen)
|
||
|
c = ubytes[q->byte];
|
||
|
const int direction = (1+(q->otherbits|c))>>8;
|
||
|
|
||
|
p = q->child[direction];
|
||
|
}
|
||
|
|
||
|
uint32_t newbyte;
|
||
|
uint32_t newotherbits;
|
||
|
|
||
|
for (newbyte = 0; newbyte < ulen; ++newbyte) {
|
||
|
if (p[newbyte] != ubytes[newbyte]) {
|
||
|
newotherbits = p[newbyte]^ubytes[newbyte];
|
||
|
goto different_byte_found;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (p[newbyte]!=0) {
|
||
|
newotherbits = p[newbyte];
|
||
|
goto different_byte_found;
|
||
|
}
|
||
|
return 1;
|
||
|
|
||
|
different_byte_found:
|
||
|
|
||
|
newotherbits |= newotherbits>>1;
|
||
|
newotherbits |= newotherbits>>2;
|
||
|
newotherbits |= newotherbits>>4;
|
||
|
newotherbits = (newotherbits&~(newotherbits>>1))^255;
|
||
|
uint8_t c = p[newbyte];
|
||
|
int newdirection = (1+(newotherbits|c))>>8;
|
||
|
|
||
|
critbit0_node* newnode;
|
||
|
if (!(newnode=malloc(sizeof(critbit0_node))))
|
||
|
return 0;
|
||
|
|
||
|
char* x;
|
||
|
if (!(x = malloc(ulen+1))) {
|
||
|
free(newnode);
|
||
|
return 0;
|
||
|
}
|
||
|
memcpy(x,ubytes,ulen+1);
|
||
|
|
||
|
newnode->byte= newbyte;
|
||
|
newnode->otherbits= newotherbits;
|
||
|
newnode->child[1-newdirection]= x;
|
||
|
|
||
|
void** wherep= &t->root;
|
||
|
for(;;) {
|
||
|
uint8_t* p = *wherep;
|
||
|
if (!((intptr_t)p&1))
|
||
|
break;
|
||
|
critbit0_node* q = (void*)(p-1);
|
||
|
if (q->byte > newbyte)break;
|
||
|
if (q->byte==newbyte && q->otherbits>newotherbits)break;
|
||
|
uint8_t c = 0;
|
||
|
if (q->byte<ulen)
|
||
|
c = ubytes[q->byte];
|
||
|
const int direction = (1+(q->otherbits|c))>>8;
|
||
|
wherep = q->child+direction;
|
||
|
}
|
||
|
|
||
|
newnode->child[newdirection]= *wherep;
|
||
|
*wherep= (void*)(1+(char*)newnode);
|
||
|
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
int critbit0_delete(critbit0_tree* t,const char* u) {
|
||
|
const uint8_t* ubytes = (void*)u;
|
||
|
const size_t ulen = strlen(u);
|
||
|
uint8_t* p = t->root;
|
||
|
void** wherep = &t->root;
|
||
|
void** whereq = 0;
|
||
|
critbit0_node* q = 0;
|
||
|
int direction = 0;
|
||
|
|
||
|
if (!p) return 0;
|
||
|
|
||
|
while ((intptr_t)p&1) {
|
||
|
whereq = wherep;
|
||
|
q = (void*)(p-1);
|
||
|
uint8_t c = 0;
|
||
|
if (q->byte<ulen)
|
||
|
c = ubytes[q->byte];
|
||
|
direction = (1+(q->otherbits|c))>>8;
|
||
|
wherep = q->child+direction;
|
||
|
p = *wherep;
|
||
|
}
|
||
|
|
||
|
if (0!=strcmp(u,(const char*)p))
|
||
|
return 0;
|
||
|
free(p);
|
||
|
|
||
|
if (!whereq) {
|
||
|
t->root = 0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
*whereq = q->child[1-direction];
|
||
|
free(q);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static void traverse(void* top) {
|
||
|
uint8_t* p = top;
|
||
|
|
||
|
if ((intptr_t)p&1) {
|
||
|
critbit0_node* q = (void*)(p-1);
|
||
|
traverse(q->child[0]);
|
||
|
traverse(q->child[1]);
|
||
|
free(q);
|
||
|
} else {
|
||
|
free(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void critbit0_clear(critbit0_tree* t) {
|
||
|
if (t->root)
|
||
|
traverse(t->root);
|
||
|
t->root = NULL;
|
||
|
}
|
||
|
|
||
|
static int allprefixed_traverse(uint8_t* top,int(*handle)(const char*,void*),void* arg) {
|
||
|
if ((uintptr_t)top&1) {
|
||
|
critbit0_node* q = (void*)(top-1);
|
||
|
int direction;
|
||
|
for (direction=0; direction<2; ++direction)
|
||
|
switch (allprefixed_traverse(q->child[direction],handle,arg)) {
|
||
|
case 1: break;
|
||
|
case 0: return 0;
|
||
|
default: return-1;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return handle((const char*)top,arg);
|
||
|
}
|
||
|
|
||
|
int critbit0_allprefixed(critbit0_tree* t,const char* prefix,int(*handle)(const char*,void*),void* arg) {
|
||
|
const uint8_t* ubytes = (void*)prefix;
|
||
|
const size_t ulen = strlen(prefix);
|
||
|
uint8_t* p = t->root;
|
||
|
uint8_t* top = p;
|
||
|
|
||
|
if (!p) return 1;
|
||
|
|
||
|
while ((uintptr_t)p&1) {
|
||
|
critbit0_node* q = (void*)(p-1);
|
||
|
uint8_t c = 0;
|
||
|
if (q->byte<ulen)
|
||
|
c=ubytes[q->byte];
|
||
|
const int direction = (1+(q->otherbits|c))>>8;
|
||
|
p = q->child[direction];
|
||
|
if (q->byte<ulen)
|
||
|
top = p;
|
||
|
}
|
||
|
|
||
|
size_t i;
|
||
|
for (i=0; i<ulen; ++i) {
|
||
|
if (p[i]!=ubytes[i])
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return allprefixed_traverse(top,handle,arg);
|
||
|
}
|
||
|
|