diff options
Diffstat (limited to 'libc-top-half/musl/src/search')
-rw-r--r-- | libc-top-half/musl/src/search/hsearch.c | 153 | ||||
-rw-r--r-- | libc-top-half/musl/src/search/insque.c | 32 | ||||
-rw-r--r-- | libc-top-half/musl/src/search/lsearch.c | 31 | ||||
-rw-r--r-- | libc-top-half/musl/src/search/tdelete.c | 49 | ||||
-rw-r--r-- | libc-top-half/musl/src/search/tdestroy.c | 16 | ||||
-rw-r--r-- | libc-top-half/musl/src/search/tfind.c | 20 | ||||
-rw-r--r-- | libc-top-half/musl/src/search/tsearch.c | 92 | ||||
-rw-r--r-- | libc-top-half/musl/src/search/tsearch.h | 13 | ||||
-rw-r--r-- | libc-top-half/musl/src/search/twalk.c | 22 |
9 files changed, 428 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/search/hsearch.c b/libc-top-half/musl/src/search/hsearch.c new file mode 100644 index 0000000..b3ac879 --- /dev/null +++ b/libc-top-half/musl/src/search/hsearch.c @@ -0,0 +1,153 @@ +#define _GNU_SOURCE +#include <stdlib.h> +#include <string.h> +#include <search.h> + +/* +open addressing hash table with 2^n table size +quadratic probing is used in case of hash collision +tab indices and hash are size_t +after resize fails with ENOMEM the state of tab is still usable + +with the posix api items cannot be iterated and length cannot be queried +*/ + +#define MINSIZE 8 +#define MAXSIZE ((size_t)-1/2 + 1) + +struct __tab { + ENTRY *entries; + size_t mask; + size_t used; +}; + +static struct hsearch_data htab; + +static int __hcreate_r(size_t, struct hsearch_data *); +static void __hdestroy_r(struct hsearch_data *); +static int __hsearch_r(ENTRY, ACTION, ENTRY **, struct hsearch_data *); + +static size_t keyhash(char *k) +{ + unsigned char *p = (void *)k; + size_t h = 0; + + while (*p) + h = 31*h + *p++; + return h; +} + +static int resize(size_t nel, struct hsearch_data *htab) +{ + size_t newsize; + size_t i, j; + ENTRY *e, *newe; + ENTRY *oldtab = htab->__tab->entries; + ENTRY *oldend = htab->__tab->entries + htab->__tab->mask + 1; + + if (nel > MAXSIZE) + nel = MAXSIZE; + for (newsize = MINSIZE; newsize < nel; newsize *= 2); + htab->__tab->entries = calloc(newsize, sizeof *htab->__tab->entries); + if (!htab->__tab->entries) { + htab->__tab->entries = oldtab; + return 0; + } + htab->__tab->mask = newsize - 1; + if (!oldtab) + return 1; + for (e = oldtab; e < oldend; e++) + if (e->key) { + for (i=keyhash(e->key),j=1; ; i+=j++) { + newe = htab->__tab->entries + (i & htab->__tab->mask); + if (!newe->key) + break; + } + *newe = *e; + } + free(oldtab); + return 1; +} + +int hcreate(size_t nel) +{ + return __hcreate_r(nel, &htab); +} + +void hdestroy(void) +{ + __hdestroy_r(&htab); +} + +static ENTRY *lookup(char *key, size_t hash, struct hsearch_data *htab) +{ + size_t i, j; + ENTRY *e; + + for (i=hash,j=1; ; i+=j++) { + e = htab->__tab->entries + (i & htab->__tab->mask); + if (!e->key || strcmp(e->key, key) == 0) + break; + } + return e; +} + +ENTRY *hsearch(ENTRY item, ACTION action) +{ + ENTRY *e; + + __hsearch_r(item, action, &e, &htab); + return e; +} + +static int __hcreate_r(size_t nel, struct hsearch_data *htab) +{ + int r; + + htab->__tab = calloc(1, sizeof *htab->__tab); + if (!htab->__tab) + return 0; + r = resize(nel, htab); + if (r == 0) { + free(htab->__tab); + htab->__tab = 0; + } + return r; +} +weak_alias(__hcreate_r, hcreate_r); + +static void __hdestroy_r(struct hsearch_data *htab) +{ + if (htab->__tab) free(htab->__tab->entries); + free(htab->__tab); + htab->__tab = 0; +} +weak_alias(__hdestroy_r, hdestroy_r); + +static int __hsearch_r(ENTRY item, ACTION action, ENTRY **retval, struct hsearch_data *htab) +{ + size_t hash = keyhash(item.key); + ENTRY *e = lookup(item.key, hash, htab); + + if (e->key) { + *retval = e; + return 1; + } + if (action == FIND) { + *retval = 0; + return 0; + } + *e = item; + if (++htab->__tab->used > htab->__tab->mask - htab->__tab->mask/4) { + if (!resize(2*htab->__tab->used, htab)) { + htab->__tab->used--; + e->key = 0; + *retval = 0; + return 0; + } + e = lookup(item.key, hash, htab); + } + *retval = e; + return 1; +} +weak_alias(__hsearch_r, hsearch_r); diff --git a/libc-top-half/musl/src/search/insque.c b/libc-top-half/musl/src/search/insque.c new file mode 100644 index 0000000..b7475d8 --- /dev/null +++ b/libc-top-half/musl/src/search/insque.c @@ -0,0 +1,32 @@ +#include <search.h> + +struct node { + struct node *next; + struct node *prev; +}; + +void insque(void *element, void *pred) +{ + struct node *e = element; + struct node *p = pred; + + if (!p) { + e->next = e->prev = 0; + return; + } + e->next = p->next; + e->prev = p; + p->next = e; + if (e->next) + e->next->prev = e; +} + +void remque(void *element) +{ + struct node *e = element; + + if (e->next) + e->next->prev = e->prev; + if (e->prev) + e->prev->next = e->next; +} diff --git a/libc-top-half/musl/src/search/lsearch.c b/libc-top-half/musl/src/search/lsearch.c new file mode 100644 index 0000000..5eb5cc2 --- /dev/null +++ b/libc-top-half/musl/src/search/lsearch.c @@ -0,0 +1,31 @@ +#include <search.h> +#include <string.h> + +void *lsearch(const void *key, void *base, size_t *nelp, size_t width, + int (*compar)(const void *, const void *)) +{ + char (*p)[width] = base; + size_t n = *nelp; + size_t i; + + for (i = 0; i < n; i++) + if (compar(key, p[i]) == 0) + return p[i]; + *nelp = n+1; + return memcpy(p[n], key, width); +} + +void *lfind(const void *key, const void *base, size_t *nelp, + size_t width, int (*compar)(const void *, const void *)) +{ + char (*p)[width] = (void *)base; + size_t n = *nelp; + size_t i; + + for (i = 0; i < n; i++) + if (compar(key, p[i]) == 0) + return p[i]; + return 0; +} + + diff --git a/libc-top-half/musl/src/search/tdelete.c b/libc-top-half/musl/src/search/tdelete.c new file mode 100644 index 0000000..b8bb924 --- /dev/null +++ b/libc-top-half/musl/src/search/tdelete.c @@ -0,0 +1,49 @@ +#include <stdlib.h> +#include <search.h> +#include "tsearch.h" + +void *tdelete(const void *restrict key, void **restrict rootp, + int(*cmp)(const void *, const void *)) +{ + if (!rootp) + return 0; + + void **a[MAXH+1]; + struct node *n = *rootp; + struct node *parent; + struct node *child; + int i=0; + /* *a[0] is an arbitrary non-null pointer that is returned when + the root node is deleted. */ + a[i++] = rootp; + a[i++] = rootp; + for (;;) { + if (!n) + return 0; + int c = cmp(key, n->key); + if (!c) + break; + a[i++] = &n->a[c>0]; + n = n->a[c>0]; + } + parent = *a[i-2]; + if (n->a[0]) { + /* free the preceding node instead of the deleted one. */ + struct node *deleted = n; + a[i++] = &n->a[0]; + n = n->a[0]; + while (n->a[1]) { + a[i++] = &n->a[1]; + n = n->a[1]; + } + deleted->key = n->key; + child = n->a[0]; + } else { + child = n->a[1]; + } + /* freed node has at most one child, move it up and rebalance. */ + free(n); + *a[--i] = child; + while (--i && __tsearch_balance(a[i])); + return parent; +} diff --git a/libc-top-half/musl/src/search/tdestroy.c b/libc-top-half/musl/src/search/tdestroy.c new file mode 100644 index 0000000..699a901 --- /dev/null +++ b/libc-top-half/musl/src/search/tdestroy.c @@ -0,0 +1,16 @@ +#define _GNU_SOURCE +#include <stdlib.h> +#include <search.h> +#include "tsearch.h" + +void tdestroy(void *root, void (*freekey)(void *)) +{ + struct node *r = root; + + if (r == 0) + return; + tdestroy(r->a[0], freekey); + tdestroy(r->a[1], freekey); + if (freekey) freekey((void *)r->key); + free(r); +} diff --git a/libc-top-half/musl/src/search/tfind.c b/libc-top-half/musl/src/search/tfind.c new file mode 100644 index 0000000..9e1cf98 --- /dev/null +++ b/libc-top-half/musl/src/search/tfind.c @@ -0,0 +1,20 @@ +#include <search.h> +#include "tsearch.h" + +void *tfind(const void *key, void *const *rootp, + int(*cmp)(const void *, const void *)) +{ + if (!rootp) + return 0; + + struct node *n = *rootp; + for (;;) { + if (!n) + break; + int c = cmp(key, n->key); + if (!c) + break; + n = n->a[c>0]; + } + return n; +} diff --git a/libc-top-half/musl/src/search/tsearch.c b/libc-top-half/musl/src/search/tsearch.c new file mode 100644 index 0000000..0de27d0 --- /dev/null +++ b/libc-top-half/musl/src/search/tsearch.c @@ -0,0 +1,92 @@ +#include <stdlib.h> +#include <search.h> +#include "tsearch.h" + +static inline int height(struct node *n) { return n ? n->h : 0; } + +static int rot(void **p, struct node *x, int dir /* deeper side */) +{ + struct node *y = x->a[dir]; + struct node *z = y->a[!dir]; + int hx = x->h; + int hz = height(z); + if (hz > height(y->a[dir])) { + /* + * x + * / \ dir z + * A y / \ + * / \ --> x y + * z D /| |\ + * / \ A B C D + * B C + */ + x->a[dir] = z->a[!dir]; + y->a[!dir] = z->a[dir]; + z->a[!dir] = x; + z->a[dir] = y; + x->h = hz; + y->h = hz; + z->h = hz+1; + } else { + /* + * x y + * / \ / \ + * A y --> x D + * / \ / \ + * z D A z + */ + x->a[dir] = z; + y->a[!dir] = x; + x->h = hz+1; + y->h = hz+2; + z = y; + } + *p = z; + return z->h - hx; +} + +/* balance *p, return 0 if height is unchanged. */ +int __tsearch_balance(void **p) +{ + struct node *n = *p; + int h0 = height(n->a[0]); + int h1 = height(n->a[1]); + if (h0 - h1 + 1u < 3u) { + int old = n->h; + n->h = h0<h1 ? h1+1 : h0+1; + return n->h - old; + } + return rot(p, n, h0<h1); +} + +void *tsearch(const void *key, void **rootp, + int (*cmp)(const void *, const void *)) +{ + if (!rootp) + return 0; + + void **a[MAXH]; + struct node *n = *rootp; + struct node *r; + int i=0; + a[i++] = rootp; + for (;;) { + if (!n) + break; + int c = cmp(key, n->key); + if (!c) + return n; + a[i++] = &n->a[c>0]; + n = n->a[c>0]; + } + r = malloc(sizeof *r); + if (!r) + return 0; + r->key = key; + r->a[0] = r->a[1] = 0; + r->h = 1; + /* insert new node, rebalance ancestors. */ + *a[--i] = r; + while (i && __tsearch_balance(a[--i])); + return r; +} diff --git a/libc-top-half/musl/src/search/tsearch.h b/libc-top-half/musl/src/search/tsearch.h new file mode 100644 index 0000000..37d11d7 --- /dev/null +++ b/libc-top-half/musl/src/search/tsearch.h @@ -0,0 +1,13 @@ +#include <search.h> +#include <features.h> + +/* AVL tree height < 1.44*log2(nodes+2)-0.3, MAXH is a safe upper bound. */ +#define MAXH (sizeof(void*)*8*3/2) + +struct node { + const void *key; + void *a[2]; + int h; +}; + +hidden int __tsearch_balance(void **); diff --git a/libc-top-half/musl/src/search/twalk.c b/libc-top-half/musl/src/search/twalk.c new file mode 100644 index 0000000..53821cd --- /dev/null +++ b/libc-top-half/musl/src/search/twalk.c @@ -0,0 +1,22 @@ +#include <search.h> +#include "tsearch.h" + +static void walk(const struct node *r, void (*action)(const void *, VISIT, int), int d) +{ + if (!r) + return; + if (r->h == 1) + action(r, leaf, d); + else { + action(r, preorder, d); + walk(r->a[0], action, d+1); + action(r, postorder, d); + walk(r->a[1], action, d+1); + action(r, endorder, d); + } +} + +void twalk(const void *root, void (*action)(const void *, VISIT, int)) +{ + walk(root, action, 0); +} |