summaryrefslogtreecommitdiffstats
path: root/libc-top-half/musl/src/search
diff options
context:
space:
mode:
Diffstat (limited to 'libc-top-half/musl/src/search')
-rw-r--r--libc-top-half/musl/src/search/hsearch.c153
-rw-r--r--libc-top-half/musl/src/search/insque.c32
-rw-r--r--libc-top-half/musl/src/search/lsearch.c31
-rw-r--r--libc-top-half/musl/src/search/tdelete.c49
-rw-r--r--libc-top-half/musl/src/search/tdestroy.c16
-rw-r--r--libc-top-half/musl/src/search/tfind.c20
-rw-r--r--libc-top-half/musl/src/search/tsearch.c92
-rw-r--r--libc-top-half/musl/src/search/tsearch.h13
-rw-r--r--libc-top-half/musl/src/search/twalk.c22
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);
+}