add critbit

master
leitner 10 years ago
parent 42eb4c9830
commit 8a6186ba03

@ -29,6 +29,7 @@
if SOCK_NONBLOCK is defined, use it instead of socket+fcntl
... but if errno==EINVAL still fall back to socket+fcntl (Robert Henney)
SECURITY: fix botched integer overflow handling logic in stralloc_ready (Giorgio)
add critbit
0.29:
save 8 bytes in taia.h for 64-bit systems

@ -11,7 +11,7 @@ MAN3DIR=${prefix}/man/man3
LIBS=byte.a fmt.a scan.a str.a uint.a open.a stralloc.a unix.a socket.a \
buffer.a mmap.a taia.a tai.a dns.a case.a mult.a array.a io.a \
textcode.a cdb.a
textcode.a cdb.a critbit.a
all: ent $(LIBS) libowfat.a libsocket t
@ -58,7 +58,7 @@ endif
# to build without diet libc support, use $ make DIET=
# see http://www.fefe.de/dietlibc/ for details about the diet libc
VPATH=str:byte:fmt:scan:uint:open:stralloc:unix:socket:buffer:mmap:textcode:taia:tai:dns:case:array:mult:io:cdb
VPATH=str:byte:fmt:scan:uint:open:stralloc:unix:socket:buffer:mmap:textcode:taia:tai:dns:case:array:mult:io:cdb:critbit
BYTE_OBJS=$(patsubst byte/%.c,%.o,$(wildcard byte/*.c))
FMT_OBJS=$(patsubst fmt/%.c,%.o,$(wildcard fmt/*.c))
@ -80,6 +80,7 @@ ARRAY_OBJS=$(patsubst array/%.c,%.o,$(wildcard array/*.c))
MULT_OBJS=$(patsubst mult/%.c,%.o,$(wildcard mult/*.c))
IO_OBJS=$(patsubst io/%.c,%.o,$(wildcard io/*.c))
CDB_OBJS=$(patsubst cdb/%.c,%.o,$(wildcard cdb/*.c))
CRITBIT_OBJS=$(patsubst critbit/%.c,%.o,$(wildcard critbit/*.c))
$(BYTE_OBJS): byte.h
$(FMT_OBJS): fmt.h
@ -99,6 +100,7 @@ $(ARRAY_OBJS): uint64.h array.h
$(MULT_OBJS): uint64.h uint32.h uint16.h safemult.h
$(IO_OBJS): uint64.h array.h io.h io_internal.h taia.h tai.h haveepoll.h havekqueue.h havesigio.h havebsdsf.h havedevpoll.h havesendfile.h
$(CDB_OBJS): cdb.h uint32.h
$(CRITBIT_OBJS): critbit.h
mult64.o: haveuint128.h
@ -133,12 +135,13 @@ array.a: $(ARRAY_OBJS)
mult.a: $(MULT_OBJS)
io.a: $(IO_OBJS)
cdb.a: $(CDB_OBJS)
critbit.a: $(CRITBIT_OBJS)
ALL_OBJS=$(DNS_OBJS) $(BYTE_OBJS) $(FMT_OBJS) $(SCAN_OBJS) \
$(STR_OBJS) $(UINT_OBJS) $(OPEN_OBJS) $(STRALLOC_OBJS) $(UNIX_OBJS) \
$(SOCKET_OBJS) $(BUFFER_OBJS) $(MMAP_OBJS) $(TEXTCODE_OBJS) \
$(TAIA_OBJS) $(TAI_OBJS) $(CASE_OBJS) $(ARRAY_OBJS) $(MULT_OBJS) \
$(IO_OBJS) $(CDB_OBJS)
$(IO_OBJS) $(CDB_OBJS) $(CRITBIT_OBJS)
libowfat.a: $(ALL_OBJS)
$(CROSS)ar cru $@ $(ALL_OBJS)

@ -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)

43
t.c

@ -23,6 +23,8 @@
#include "iob.h"
#include "safemult.h"
#include "iarray.h"
#include "critbit.h"
#include <assert.h>
#include "CAS.h"
@ -47,7 +49,47 @@ static int64 writecb(int64 fd,const void* buf,uint64 n) {
return -1;
}
static int ret0(const char* s,void* foo) {
(void)foo;
assert(strcmp(s,"fnord")==0);
return 0;
}
static int ret1(const char* s,void* foo) {
static int i;
(void)foo;
switch (i) {
case 0: assert(strcmp(s,"fnord")==0); break;
case 1: assert(strcmp(s,"fnord2")==0); break;
default: return -1;
}
++i;
return 1;
}
int main(int argc,char* argv[]) {
static critbit0_tree t;
assert(critbit0_insert(&t,"fnord")==2);
assert(critbit0_insert(&t,"fnord2")==2);
assert(critbit0_insert(&t,"fnord2")==1);
assert(critbit0_contains(&t,"foo")==0);
assert(critbit0_contains(&t,"fnord")==1);
assert(critbit0_allprefixed(&t,"fnord",ret1,NULL)==1);
assert(critbit0_allprefixed(&t,"fnord",ret0,NULL)==0);
assert(critbit0_delete(&t,"fnord2")==1);
assert(critbit0_delete(&t,"foo")==0);
#if 0
int s = socket_tcp6();
#endif
#if 0
iarray i;
iarray_init(&i,sizeof(size_t));
printf("%p\n",iarray_get(&i,0));
printf("%p\n",iarray_allocate(&i,0));
printf("%p\n",iarray_allocate(&i,0));
printf("%p\n",iarray_get(&i,0));
#endif
#if 0
char buf[1024];
size_t l;
unsigned char c;
@ -70,6 +112,7 @@ int main(int argc,char* argv[]) {
f 0 9 d 8 4 9 e
*/
#endif
#if 0
static size_t x;
x=23;

Loading…
Cancel
Save