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.6 KiB
C

#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); // gcc -fanalyze false positive
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);
}