libavl: lookup can return the closest match

This commit is contained in:
spew 2017-04-22 13:59:37 -05:00
parent f2b7f24e4e
commit 9cf5198145
9 changed files with 34 additions and 25 deletions

View file

@ -15,8 +15,9 @@ struct Avltree {
Avl *root; Avl *root;
}; };
Avltree *avlcreate(int(*cmp)(Avl*, Avl*)); Avltree *avlinit(Avltree*, int(*)(Avl*, Avl*));
Avl *avllookup(Avltree*, Avl*); Avltree *avlcreate(int(*)(Avl*, Avl*));
Avl *avllookup(Avltree*, Avl*, int);
Avl *avldelete(Avltree*, Avl*); Avl *avldelete(Avltree*, Avl*);
Avl *avlinsert(Avltree*, Avl*); Avl *avlinsert(Avltree*, Avl*);
Avl *avlnext(Avl*); Avl *avlnext(Avl*);

View file

@ -30,7 +30,7 @@ struct Avltree {
Avltree *avlcreate(int(*cmp)(Avl*, Avl*)); Avltree *avlcreate(int(*cmp)(Avl*, Avl*));
Avl *avlinsert(Avltree *tree, Avl *new); Avl *avlinsert(Avltree *tree, Avl *new);
Avl *avldelete(Avltree *tree, Avl *key); Avl *avldelete(Avltree *tree, Avl *key);
Avl *avllookup(Avltree *tree, Avl *key); Avl *avllookup(Avltree *tree, Avl *key, int dir);
Avl *avlnext(Avl *n); Avl *avlnext(Avl *n);
Avl *avlprev(Avl *n); Avl *avlprev(Avl *n);
@ -55,13 +55,15 @@ node into the tree and returns an existing
node with the same key that has been removed node with the same key that has been removed
from the tree and may be freed. from the tree and may be freed.
.I Avllookup .I Avllookup
returns the searches for a given key and returns
node that matches the key or the closest node less than the given key,
.B nil .BR nil ,
if no node matches. or the closest node greater than the key depending on whether
.I dir
is less than, equal to, or greater than zero, respectively.
.I Avldelete .I Avldelete
removes the node matching the key from the tree and returns removes the node matching the key from the tree and returns
it. It returns nil of no matching key is found. it. It returns nil if no matching key is found.
.PP .PP
.I Avlnext .I Avlnext
returns the next returns the next

View file

@ -22,7 +22,7 @@ mtreeisdup(Mailbox *mb, Message *m)
return 0; return 0;
memset(&t, 0, sizeof t); memset(&t, 0, sizeof t);
t.m = m; t.m = m;
if(avllookup(mb->mtree, &t)) if(avllookup(mb->mtree, &t, 0))
return 1; return 1;
return 0; return 0;
} }
@ -36,7 +36,7 @@ mtreefind(Mailbox *mb, uchar *digest)
m0.digest = digest; m0.digest = digest;
memset(&t, 0, sizeof t); memset(&t, 0, sizeof t);
t.m = &m0; t.m = &m0;
if(p = (Mtree*)avllookup(mb->mtree, &t)) if(p = (Mtree*)avllookup(mb->mtree, &t, 0))
return p->m; return p->m;
return nil; return nil;
} }
@ -65,7 +65,7 @@ mtreedelete(Mailbox *mb, Message *m)
if(m->deleted & ~Deleted){ if(m->deleted & ~Deleted){
if(m->digest == nil) if(m->digest == nil)
return; return;
p = (Mtree*)avllookup(mb->mtree, &t); p = (Mtree*)avllookup(mb->mtree, &t, 0);
if(p == nil || p->m != m) if(p == nil || p->m != m)
return; return;
p = (Mtree*)avldelete(mb->mtree, &t); p = (Mtree*)avldelete(mb->mtree, &t);

View file

@ -25,7 +25,7 @@ fstreefind(Box *mb, int id)
memset(&t, 0, sizeof t); memset(&t, 0, sizeof t);
m0.id = id; m0.id = id;
t.m = &m0; t.m = &m0;
if(p = (Fstree*)avllookup(mb->fstree, &t)) if(p = (Fstree*)avllookup(mb->fstree, &t, 0))
return p->m; return p->m;
return nil; return nil;
} }

View file

@ -100,7 +100,7 @@ rdimp(Biobuf *b, Box *box)
memset(&t, 0, sizeof t); memset(&t, 0, sizeof t);
m0.info[Idigest] = f[0]; m0.info[Idigest] = f[0];
t.m = &m0; t.m = &m0;
p = (Mtree*)avllookup(mtree, &t); p = (Mtree*)avllookup(mtree, &t, 0);
if(p){ if(p){
m = p->m; m = p->m;
if(m->uid && m->uid != u){ if(m->uid && m->uid != u){

View file

@ -51,7 +51,7 @@ havevisited(uchar score[VtScoreSize], int type)
return 0; return 0;
memmove(a.score, score, VtScoreSize); memmove(a.score, score, VtScoreSize);
a.type = type; a.type = type;
return avllookup(scoretree, &a) != nil; return avllookup(scoretree, &a, 0) != nil;
} }
static void static void

View file

@ -6,9 +6,9 @@
int extraproc = -1, throttle; int extraproc = -1, throttle;
static QLock* golock; static QLock *golock;
static Rendez* gorend; static Rendez *gorend;
static int* go; static int *go;
static QLock runninglock; static QLock runninglock;
static Rendez runningrend; static Rendez runningrend;

View file

@ -413,7 +413,7 @@ sym(char *name)
Sym *s, l; Sym *s, l;
l.name = name; l.name = name;
s = (Sym*)avllookup(syms, &l); s = (Sym*)avllookup(syms, &l, 0);
if(s != nil) if(s != nil)
return s; return s;

View file

@ -4,10 +4,6 @@
/* See Knuth Volume 3, 6.2.3 */ /* See Knuth Volume 3, 6.2.3 */
Avl *avllookup(Avltree*, Avl*);
Avl *avldelete(Avltree*, Avl*);
Avl *avlinsert(Avltree*, Avl*);
Avltree* Avltree*
avlcreate(int (*cmp)(Avl*, Avl*)) avlcreate(int (*cmp)(Avl*, Avl*))
{ {
@ -16,32 +12,42 @@ avlcreate(int (*cmp)(Avl*, Avl*))
t = malloc(sizeof(*t)); t = malloc(sizeof(*t));
if(t == nil) if(t == nil)
return nil; return nil;
return avlinit(t, cmp);
}
Avltree*
avlinit(Avltree *t, int (*cmp)(Avl*, Avl*))
{
t->cmp = cmp; t->cmp = cmp;
t->root = nil; t->root = nil;
return t; return t;
} }
Avl* Avl*
avllookup(Avltree *t, Avl *k) avllookup(Avltree *t, Avl *k, int d)
{ {
Avl *h; Avl *h, *n;
int c; int c;
n = nil;
h = t->root; h = t->root;
while(h != nil){ while(h != nil){
c = (t->cmp)(k, h); c = (t->cmp)(k, h);
if(c < 0){ if(c < 0){
if(d > 0)
n = h;
h = h->c[0]; h = h->c[0];
continue; continue;
} }
if(c > 0){ if(c > 0){
if(d < 0)
n = h;
h = h->c[1]; h = h->c[1];
continue; continue;
} }
return h; return h;
} }
return nil; return n;
} }
static int insert(int (*)(Avl*, Avl*), Avl*, Avl**, Avl*, Avl**); static int insert(int (*)(Avl*, Avl*), Avl*, Avl**, Avl*, Avl**);