add critbit
parent
42eb4c9830
commit
8a6186ba03
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef CRITBIT_H_
|
||||||
|
#define CRITBIT_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *root;
|
||||||
|
} critbit0_tree;
|
||||||
|
|
||||||
|
int critbit0_contains(critbit0_tree *t, const char *u);
|
||||||
|
int critbit0_insert(critbit0_tree *t, const char *u);
|
||||||
|
int critbit0_delete(critbit0_tree *t, const char *u);
|
||||||
|
void critbit0_clear(critbit0_tree *t);
|
||||||
|
int critbit0_allprefixed(critbit0_tree *t, const char *prefix,
|
||||||
|
int (*handle) (const char *, void *), void *arg);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,227 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
|||||||
|
.TH critbit0_allprefixed 3
|
||||||
|
.SH NAME
|
||||||
|
critbit0_allprefixed \- search a critbit tree by prefix
|
||||||
|
.SH SYNTAX
|
||||||
|
.B #include <critbit.h>
|
||||||
|
|
||||||
|
critbit0_tree cb = { 0 };
|
||||||
|
|
||||||
|
int \fBcritbit0_allprefixed\fP(critbit0_tree* \fIcb\fR,const char* \fIprefix\fR,
|
||||||
|
int (*handle)(const char*,void*),void* arg);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
critbit0_allprefixed calls the \fIhandle\fR function on all members of
|
||||||
|
\fIcb\fR that start with \fIprefix\fR. It passes \fIarg\fR as second
|
||||||
|
argument to \fIhandle\fR.
|
||||||
|
|
||||||
|
If \fIhandle\fR returns 0, the search stops and critbit0_allprefixed
|
||||||
|
returns 0.
|
||||||
|
|
||||||
|
If \fIhandle\fR returns 1, the search continues and critbit0_allprefixed
|
||||||
|
returns 1 if all keys with the given prefix were handled.
|
||||||
|
|
||||||
|
If \fIhandle\fR returns something else, the search stops and
|
||||||
|
critbit0_allprefixed returns -1.
|
||||||
|
.SH "RETURN VALUE"
|
||||||
|
1 if all keys were found and handled (or if there were no keys with that
|
||||||
|
prefix).
|
||||||
|
|
||||||
|
0 if at least one key was found, \fIhandle\fR was called and returned 0.
|
||||||
|
|
||||||
|
-1 if at least one key was found, \fIhandle\fR was called and returned
|
||||||
|
something other than 0 or 1.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
critbit0_contains(3)
|
@ -0,0 +1,16 @@
|
|||||||
|
.TH critbit0_clear 3
|
||||||
|
.SH NAME
|
||||||
|
critbit0_clear \- free all memory associated with a critbit tree
|
||||||
|
.SH SYNTAX
|
||||||
|
.B #include <critbit.h>
|
||||||
|
|
||||||
|
critbit0_tree cb = { 0 };
|
||||||
|
|
||||||
|
void \fBcritbit0_clear\fP(critbit0_tree* \fIcb\fR);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
critbit0_clear deletes all keys in \fIcb\fR and frees all memory
|
||||||
|
associated with it.
|
||||||
|
.SH "RETURN VALUE"
|
||||||
|
none.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
critbit0_delete(3)
|
@ -0,0 +1,17 @@
|
|||||||
|
.TH critbit0_contains 3
|
||||||
|
.SH NAME
|
||||||
|
critbit0_contains \- check whether a string is in the critbit tree
|
||||||
|
.SH SYNTAX
|
||||||
|
.B #include <critbit.h>
|
||||||
|
|
||||||
|
critbit0_tree cb = { 0 };
|
||||||
|
|
||||||
|
int \fBcritbit0_contains\fP(critbit0_tree* \fIcb\fR,const char* \fIstr\fR);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
critbit0_contains looks up the given string in the critbit0 tree.
|
||||||
|
If \fIstr\fR is in \fIcb\fR, critbit0_contains returns 1. Otherwise it
|
||||||
|
returns 0.
|
||||||
|
.SH "RETURN VALUE"
|
||||||
|
1 if the key was found, 0 otherwise.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
critbit0_insert(3)
|
@ -0,0 +1,18 @@
|
|||||||
|
.TH critbit0_delete 3
|
||||||
|
.SH NAME
|
||||||
|
critbit0_delete \- delete a string from a critbit tree
|
||||||
|
.SH SYNTAX
|
||||||
|
.B #include <critbit.h>
|
||||||
|
|
||||||
|
critbit0_tree cb = { 0 };
|
||||||
|
|
||||||
|
int \fBcritbit0_delete\fP(critbit0_tree* \fIcb\fR,const char* \fIstr\fR);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
critbit0_delete attempts to delete a string from a critbit0 tree.
|
||||||
|
If \fIstr\fR is in \fIcb\fR, critbit0_delete removes it and returns 1.
|
||||||
|
If \fIstr\fR is not in \fIcb\fR, critbit0_delete leaves it alone and
|
||||||
|
returns 0.
|
||||||
|
.SH "RETURN VALUE"
|
||||||
|
1 if it was in cb and has now been removed, 0 if it was not in cb.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
critbit0_insert(3)
|
@ -0,0 +1,21 @@
|
|||||||
|
.TH critbit0_insert 3
|
||||||
|
.SH NAME
|
||||||
|
critbit0_insert \- insert a string into a critbit tree
|
||||||
|
.SH SYNTAX
|
||||||
|
.B #include <critbit.h>
|
||||||
|
|
||||||
|
critbit0_tree cb = { 0 };
|
||||||
|
|
||||||
|
int \fBcritbit0_insert\fP(critbit0_tree* \fIcb\fR,const char* \fIstr\fR);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
critbit0_insert attempts to insert a string into a critbit0 tree.
|
||||||
|
If \fIstr\fR is already in \fIcb\fR, critbit0_insert returns 1.
|
||||||
|
If \fIstr\fR is not in \fIcb\fR, it is inserted and critbit0_insert
|
||||||
|
returns 2.
|
||||||
|
If there is a memory allocation failure on the way, critbit0_insert
|
||||||
|
leaves \fIcb\fR alone and returns 0.
|
||||||
|
.SH "RETURN VALUE"
|
||||||
|
2 if the key was inserted, 1 if it was already in cb, 0 on memory
|
||||||
|
allocation failure.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
critbit0_contains(3)
|
Loading…
Reference in New Issue