diff --git a/libc/isystem/search.h b/libc/isystem/search.h new file mode 100644 index 000000000..7b43512d2 --- /dev/null +++ b/libc/isystem/search.h @@ -0,0 +1,6 @@ +#ifndef LIBC_ISYSTEM_SEARCH_H +#define LIBC_ISYSTEM_SEARCH_H + +#include "third_party/musl/search.h" + +#endif /* LIBC_ISYSTEM_SEARCH_H */ diff --git a/third_party/musl/hsearch.c b/third_party/musl/hsearch.c new file mode 100644 index 000000000..c8936f5f2 --- /dev/null +++ b/third_party/musl/hsearch.c @@ -0,0 +1,197 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2020 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#include "libc/str/str.h" +#define _GNU_SOURCE +#include "third_party/musl/search.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2020 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); +// clang-format off + +/* +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; + size_t oldsize = htab->__tab->mask + 1; + ENTRY *e, *newe; + ENTRY *oldtab = htab->__tab->entries; + + 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 < oldtab + oldsize; 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; +} + + +int hcreate_r(size_t nel, struct hsearch_data *htab) { + return __hcreate_r(nel, htab); +} + +static void __hdestroy_r(struct hsearch_data *htab) +{ + if (htab->__tab) free(htab->__tab->entries); + free(htab->__tab); + htab->__tab = 0; +} + +void hdestroy_r(struct hsearch_data *htab) { + __hdestroy_r(htab); +} + +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; +} + +int hsearch_r(ENTRY item, ACTION action, ENTRY **retval, struct hsearch_data *htab) +{ + return __hsearch_r(item, action, retval, htab); +} diff --git a/third_party/musl/insque.c b/third_party/musl/insque.c new file mode 100644 index 000000000..1d91fe3c9 --- /dev/null +++ b/third_party/musl/insque.c @@ -0,0 +1,66 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2020 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/musl/search.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2020 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); +// clang-format off + + +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/third_party/musl/lsearch.c b/third_party/musl/lsearch.c new file mode 100644 index 000000000..f1c1356da --- /dev/null +++ b/third_party/musl/lsearch.c @@ -0,0 +1,66 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2020 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#include "libc/str/str.h" +#include "third_party/musl/search.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2020 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); +// clang-format off + + +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/third_party/musl/search.h b/third_party/musl/search.h new file mode 100644 index 000000000..50d263df4 --- /dev/null +++ b/third_party/musl/search.h @@ -0,0 +1,50 @@ +#ifndef COSMOPOLITAN_THIRDPARTY_MUSL_SEARCH_H +#define COSMOPOLITAN_THIRDPARTY_MUSL_SEARCH_H + +typedef enum { FIND, ENTER } ACTION; +typedef enum { preorder, postorder, endorder, leaf } VISIT; + +typedef struct entry { + char *key; + void *data; +} ENTRY; + +int hcreate(size_t); +void hdestroy(void); +ENTRY *hsearch(ENTRY, ACTION); + +#ifdef _GNU_SOURCE +struct hsearch_data { + struct __tab *__tab; + unsigned int __unused1; + unsigned int __unused2; +}; + +int hcreate_r(size_t, struct hsearch_data *); +void hdestroy_r(struct hsearch_data *); +int hsearch_r(ENTRY, ACTION, ENTRY **, struct hsearch_data *); +#endif + +void insque(void *, void *); +void remque(void *); + +void *lsearch(const void *, void *, size_t *, size_t, + int (*)(const void *, const void *)); +void *lfind(const void *, const void *, size_t *, size_t, + int (*)(const void *, const void *)); + +void *tdelete(const void *__restrict, void **__restrict, int(*)(const void *, const void *)); +void *tfind(const void *, void *const *, int(*)(const void *, const void *)); +void *tsearch(const void *, void **, int (*)(const void *, const void *)); +void twalk(const void *, void (*)(const void *, VISIT, int)); + +#ifdef _GNU_SOURCE +struct qelem { + struct qelem *q_forw, *q_back; + char q_data[1]; +}; + +void tdestroy(void *, void (*)(void *)); +#endif + +#endif diff --git a/third_party/musl/tdelete.c b/third_party/musl/tdelete.c new file mode 100644 index 000000000..731d94fb7 --- /dev/null +++ b/third_party/musl/tdelete.c @@ -0,0 +1,83 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2020 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#include "third_party/musl/search.h" +#include "third_party/musl/tsearch.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2020 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); +// clang-format off + + +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/third_party/musl/tdestroy.c b/third_party/musl/tdestroy.c new file mode 100644 index 000000000..ff2baca89 --- /dev/null +++ b/third_party/musl/tdestroy.c @@ -0,0 +1,49 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2020 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#define _GNU_SOURCE +#include "third_party/musl/search.h" +#include "third_party/musl/tsearch.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2020 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); +// clang-format off + +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/third_party/musl/tfind.c b/third_party/musl/tfind.c new file mode 100644 index 000000000..166a47131 --- /dev/null +++ b/third_party/musl/tfind.c @@ -0,0 +1,53 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2020 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/musl/search.h" +#include "third_party/musl/tsearch.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2020 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); +// clang-format off + +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/third_party/musl/tsearch.c b/third_party/musl/tsearch.c new file mode 100644 index 000000000..0b932e93d --- /dev/null +++ b/third_party/musl/tsearch.c @@ -0,0 +1,126 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2020 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#include "libc/str/str.h" +#include "third_party/musl/search.h" +#include "third_party/musl/tsearch.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2020 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); +// clang-format off + +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