mirror of /home/gitosis/repositories/libowfat.git
parent
5b2ef494ef
commit
d3b4a5073d
10 changed files with 405 additions and 3 deletions
@ -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