add critbit
This commit is contained in:
parent
42eb4c9830
commit
8a6186ba03
1
CHANGES
1
CHANGES
@ -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)
|
||||
|
23
critbit.h
Normal file
23
critbit.h
Normal file
@ -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
|
227
critbit/critbit.c
Normal file
227
critbit/critbit.c
Normal file
@ -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);
|
||||
}
|
||||
|
33
critbit/critbit0_allprefixed.3
Normal file
33
critbit/critbit0_allprefixed.3
Normal file
@ -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)
|
16
critbit/critbit0_clear.3
Normal file
16
critbit/critbit0_clear.3
Normal file
@ -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)
|
17
critbit/critbit0_contains.3
Normal file
17
critbit/critbit0_contains.3
Normal file
@ -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)
|
18
critbit/critbit0_delete.3
Normal file
18
critbit/critbit0_delete.3
Normal file
@ -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)
|
21
critbit/critbit0_insert.3
Normal file
21
critbit/critbit0_insert.3
Normal file
@ -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
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…
x
Reference in New Issue
Block a user