diff --git a/src/system/libroot/posix/glibc/misc/Jamfile b/src/system/libroot/posix/glibc/misc/Jamfile index 1c9152bffc..eb793f2f39 100644 --- a/src/system/libroot/posix/glibc/misc/Jamfile +++ b/src/system/libroot/posix/glibc/misc/Jamfile @@ -20,11 +20,6 @@ for architectureObject in [ MultiArchSubDirSetup ] { UsePrivateHeaders libroot ; MergeObject <$(architecture)>posix_gnu_misc.o : - hsearch.c - hsearch_r.c - insremque.c - lsearch.c - tsearch.c efgcvt.c efgcvt_r.c ; diff --git a/src/system/libroot/posix/glibc/misc/hsearch.c b/src/system/libroot/posix/glibc/misc/hsearch.c deleted file mode 100644 index 79d38f5d0f..0000000000 --- a/src/system/libroot/posix/glibc/misc/hsearch.c +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. - Contributed by Ulrich Drepper - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include - -/* The non-reentrant version use a global space for storing the table. */ -static struct hsearch_data htab; - - -/* Define the non-reentrant function using the reentrant counterparts. */ -ENTRY * -hsearch (item, action) - ENTRY item; - ACTION action; -{ - ENTRY *result; - - (void) hsearch_r (item, action, &result, &htab); - - return result; -} - - -int -hcreate (nel) - size_t nel; -{ - return hcreate_r (nel, &htab); -} - - -void -__hdestroy () -{ - hdestroy_r (&htab); -} -weak_alias (__hdestroy, hdestroy) - -/* Make sure the table is freed if we want to free everything before - exiting. */ -text_set_element (__libc_subfreeres, __hdestroy); diff --git a/src/system/libroot/posix/glibc/misc/hsearch_r.c b/src/system/libroot/posix/glibc/misc/hsearch_r.c deleted file mode 100644 index 0dec896f5f..0000000000 --- a/src/system/libroot/posix/glibc/misc/hsearch_r.c +++ /dev/null @@ -1,230 +0,0 @@ -/* Copyright (C) 1993,1995-1997,2002,2005,2007,2008,2009 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1993. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include -#include - -#include - -/* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 - [Knuth] The Art of Computer Programming, part 3 (6.4) */ - - -/* The reentrant version has no static variables to maintain the state. - Instead the interface of all functions is extended to take an argument - which describes the current status. */ -typedef struct _ENTRY -{ - unsigned int used; - ENTRY entry; -} -_ENTRY; - - -/* For the used double hash method the table size has to be a prime. To - correct the user given table size we need a prime test. This trivial - algorithm is adequate because - a) the code is (most probably) called a few times per program run and - b) the number is small because the table must fit in the core */ -static int -isprime (unsigned int number) -{ - /* no even number will be passed */ - unsigned int div = 3; - - while (div * div < number && number % div != 0) - div += 2; - - return number % div != 0; -} - - -/* Before using the hash table we must allocate memory for it. - Test for an existing table are done. We allocate one element - more as the found prime number says. This is done for more effective - indexing as explained in the comment for the hsearch function. - The contents of the table is zeroed, especially the field used - becomes zero. */ -int -hcreate_r (nel, htab) - size_t nel; - struct hsearch_data *htab; -{ - /* Test for correct arguments. */ - if (htab == NULL) - { - __set_errno (EINVAL); - return 0; - } - - /* There is still another table active. Return with error. */ - if (htab->table != NULL) - return 0; - - /* We need a size of at least 3. Otherwise the hash functions we - use will not work. */ - if (nel < 3) - nel = 3; - /* Change nel to the first prime number not smaller as nel. */ - nel |= 1; /* make odd */ - while (!isprime (nel)) - nel += 2; - - htab->size = nel; - htab->filled = 0; - - /* allocate memory and zero out */ - htab->table = (_ENTRY *) calloc (htab->size + 1, sizeof (_ENTRY)); - if (htab->table == NULL) - return 0; - - /* everything went alright */ - return 1; -} -libc_hidden_def (hcreate_r) - - -/* After using the hash table it has to be destroyed. The used memory can - be freed and the local static variable can be marked as not used. */ -void -hdestroy_r (htab) - struct hsearch_data *htab; -{ - /* Test for correct arguments. */ - if (htab == NULL) - { - __set_errno (EINVAL); - return; - } - - /* Free used memory. */ - free (htab->table); - - /* the sign for an existing table is an value != NULL in htable */ - htab->table = NULL; -} -libc_hidden_def (hdestroy_r) - - -/* This is the search function. It uses double hashing with open addressing. - The argument item.key has to be a pointer to an zero terminated, most - probably strings of chars. The function for generating a number of the - strings is simple but fast. It can be replaced by a more complex function - like ajw (see [Aho,Sethi,Ullman]) if the needs are shown. - - We use an trick to speed up the lookup. The table is created by hcreate - with one more element available. This enables us to use the index zero - special. This index will never be used because we store the first hash - index in the field used where zero means not used. Every other value - means used. The used field can be used as a first fast comparison for - equality of the stored and the parameter value. This helps to prevent - unnecessary expensive calls of strcmp. */ -int -hsearch_r (item, action, retval, htab) - ENTRY item; - ACTION action; - ENTRY **retval; - struct hsearch_data *htab; -{ - unsigned int hval; - unsigned int count; - unsigned int len = strlen (item.key); - unsigned int idx; - - /* Compute an value for the given string. Perhaps use a better method. */ - hval = len; - count = len; - while (count-- > 0) - { - hval <<= 4; - hval += item.key[count]; - } - if (hval == 0) - ++hval; - - /* First hash function: simply take the modul but prevent zero. */ - idx = hval % htab->size + 1; - - if (htab->table[idx].used) - { - /* Further action might be required according to the action value. */ - if (htab->table[idx].used == hval - && strcmp (item.key, htab->table[idx].entry.key) == 0) - { - *retval = &htab->table[idx].entry; - return 1; - } - { - /* Second hash function, as suggested in [Knuth] */ - unsigned int hval2 = 1 + hval % (htab->size - 2); - unsigned int first_idx = idx; - - do - { - /* Because SIZE is prime this guarantees to step through all - available indeces. */ - if (idx <= hval2) - idx = htab->size + idx - hval2; - else - idx -= hval2; - - /* If we visited all entries leave the loop unsuccessfully. */ - if (idx == first_idx) - break; - - /* If entry is found use it. */ - if (htab->table[idx].used == hval - && strcmp (item.key, htab->table[idx].entry.key) == 0) - { - *retval = &htab->table[idx].entry; - return 1; - } - } - while (htab->table[idx].used); - } - } - - /* An empty bucket has been found. */ - if (action == ENTER) - { - /* If table is full and another entry should be entered return - with error. */ - if (htab->filled == htab->size) - { - __set_errno (ENOMEM); - *retval = NULL; - return 0; - } - - htab->table[idx].used = hval; - htab->table[idx].entry = item; - - ++htab->filled; - - *retval = &htab->table[idx].entry; - return 1; - } - - __set_errno (ESRCH); - *retval = NULL; - return 0; -} -libc_hidden_def (hsearch_r) diff --git a/src/system/libroot/posix/glibc/misc/insremque.c b/src/system/libroot/posix/glibc/misc/insremque.c deleted file mode 100644 index e366ac8063..0000000000 --- a/src/system/libroot/posix/glibc/misc/insremque.c +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include - -/* Insert ELEM into a doubly-linked list, after PREV. */ - -void -insque (void *elem, void *prev) -{ - struct qelem *next = ((struct qelem *) prev)->q_forw; - ((struct qelem *) prev)->q_forw = (struct qelem *) elem; - if (next != NULL) - next->q_back = (struct qelem *) elem; - ((struct qelem *) elem)->q_forw = next; - ((struct qelem *) elem)->q_back = (struct qelem *) prev; -} - -/* Unlink ELEM from the doubly-linked list that it is in. */ - -void -remque (void *elem) -{ - struct qelem *next = ((struct qelem *) elem)->q_forw; - struct qelem *prev = ((struct qelem *) elem)->q_back; - if (next != NULL) - next->q_back = prev; - if (prev != NULL) - prev->q_forw = (struct qelem *) next; -} diff --git a/src/system/libroot/posix/glibc/misc/lsearch.c b/src/system/libroot/posix/glibc/misc/lsearch.c deleted file mode 100644 index 057ff396e1..0000000000 --- a/src/system/libroot/posix/glibc/misc/lsearch.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Linear search functions. - Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1996. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include - - -void * -lsearch (const void *key, void *base, size_t *nmemb, size_t size, - __compar_fn_t compar) -{ - void *result; - - /* Try to find it. */ - result = lfind (key, base, nmemb, size, compar); - if (result == NULL) - { - /* Not available. Insert at the end. */ - result = memcpy (base + (*nmemb) * size, key, size); - ++(*nmemb); - } - - return result; -} - - -void * -lfind (const void *key, const void *base, size_t *nmemb, size_t size, - __compar_fn_t compar) -{ - const void *result = base; - size_t cnt = 0; - - while (cnt < *nmemb && (*compar) (key, result) != 0) - { - result += size; - ++cnt; - } - - return cnt < *nmemb ? (void *) result : NULL; -} -libc_hidden_def (lfind) diff --git a/src/system/libroot/posix/glibc/misc/search.h b/src/system/libroot/posix/glibc/misc/search.h deleted file mode 100644 index 2ffba697b0..0000000000 --- a/src/system/libroot/posix/glibc/misc/search.h +++ /dev/null @@ -1,175 +0,0 @@ -/* Declarations for System V style searching functions. - Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _SEARCH_H -#define _SEARCH_H 1 - -#include - -#define __need_size_t -#include - -__BEGIN_DECLS - -#if defined __USE_SVID || defined __USE_XOPEN_EXTENDED -/* Prototype structure for a linked-list data structure. - This is the type used by the `insque' and `remque' functions. */ - -# ifdef __USE_GNU -struct qelem - { - struct qelem *q_forw; - struct qelem *q_back; - char q_data[1]; - }; -# endif - - -/* Insert ELEM into a doubly-linked list, after PREV. */ -extern void insque (void *__elem, void *__prev) __THROW; - -/* Unlink ELEM from the doubly-linked list that it is in. */ -extern void remque (void *__elem) __THROW; -#endif - - -/* For use with hsearch(3). */ -#ifndef __COMPAR_FN_T -# define __COMPAR_FN_T -typedef int (*__compar_fn_t) (__const void *, __const void *); - -# ifdef __USE_GNU -typedef __compar_fn_t comparison_fn_t; -# endif -#endif - -/* Action which shall be performed in the call the hsearch. */ -typedef enum - { - FIND, - ENTER - } -ACTION; - -typedef struct entry - { - char *key; - void *data; - } -ENTRY; - -/* Opaque type for internal use. */ -struct _ENTRY; - -/* Family of hash table handling functions. The functions also - have reentrant counterparts ending with _r. The non-reentrant - functions all work on a signle internal hashing table. */ - -/* Search for entry matching ITEM.key in internal hash table. If - ACTION is `FIND' return found entry or signal error by returning - NULL. If ACTION is `ENTER' replace existing data (if any) with - ITEM.data. */ -extern ENTRY *hsearch (ENTRY __item, ACTION __action) __THROW; - -/* Create a new hashing table which will at most contain NEL elements. */ -extern int hcreate (size_t __nel) __THROW; - -/* Destroy current internal hashing table. */ -extern void hdestroy (void) __THROW; - -#ifdef __USE_GNU -/* Data type for reentrant functions. */ -struct hsearch_data - { - struct _ENTRY *table; - unsigned int size; - unsigned int filled; - }; - -/* Reentrant versions which can handle multiple hashing tables at the - same time. */ -extern int hsearch_r (ENTRY __item, ACTION __action, ENTRY **__retval, - struct hsearch_data *__htab) __THROW; -extern int hcreate_r (size_t __nel, struct hsearch_data *__htab) __THROW; -extern void hdestroy_r (struct hsearch_data *__htab) __THROW; -#endif - - -/* The tsearch routines are very interesting. They make many - assumptions about the compiler. It assumes that the first field - in node must be the "key" field, which points to the datum. - Everything depends on that. */ -/* For tsearch */ -typedef enum -{ - preorder, - postorder, - endorder, - leaf -} -VISIT; - -/* Search for an entry matching the given KEY in the tree pointed to - by *ROOTP and insert a new element if not found. */ -extern void *tsearch (__const void *__key, void **__rootp, - __compar_fn_t __compar); - -/* Search for an entry matching the given KEY in the tree pointed to - by *ROOTP. If no matching entry is available return NULL. */ -extern void *tfind (__const void *__key, void *__const *__rootp, - __compar_fn_t __compar); - -/* Remove the element matching KEY from the tree pointed to by *ROOTP. */ -extern void *tdelete (__const void *__restrict __key, - void **__restrict __rootp, - __compar_fn_t __compar); - -#ifndef __ACTION_FN_T -# define __ACTION_FN_T -typedef void (*__action_fn_t) (__const void *__nodep, VISIT __value, - int __level); -#endif - -/* Walk through the whole tree and call the ACTION callback for every node - or leaf. */ -extern void twalk (__const void *__root, __action_fn_t __action); - -#ifdef __USE_GNU -/* Callback type for function to free a tree node. If the keys are atomic - data this function should do nothing. */ -typedef void (*__free_fn_t) (void *__nodep); - -/* Destroy the whole tree, call FREEFCT for each node or leaf. */ -extern void tdestroy (void *__root, __free_fn_t __freefct); -#endif - - -/* Perform linear search for KEY by comparing by COMPAR in an array - [BASE,BASE+NMEMB*SIZE). */ -extern void *lfind (__const void *__key, __const void *__base, - size_t *__nmemb, size_t __size, __compar_fn_t __compar); - -/* Perform linear search for KEY by comparing by COMPAR function in - array [BASE,BASE+NMEMB*SIZE) and insert entry if not found. */ -extern void *lsearch (__const void *__key, void *__base, - size_t *__nmemb, size_t __size, __compar_fn_t __compar); - -__END_DECLS - -#endif /* search.h */ diff --git a/src/system/libroot/posix/glibc/misc/tsearch.c b/src/system/libroot/posix/glibc/misc/tsearch.c deleted file mode 100644 index 6bca0a9f67..0000000000 --- a/src/system/libroot/posix/glibc/misc/tsearch.c +++ /dev/null @@ -1,656 +0,0 @@ -/* Copyright (C) 1995, 1996, 1997, 2000 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Bernd Schmidt , 1997. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -/* Tree search for red/black trees. - The algorithm for adding nodes is taken from one of the many "Algorithms" - books by Robert Sedgewick, although the implementation differs. - The algorithm for deleting nodes can probably be found in a book named - "Introduction to Algorithms" by Cormen/Leiserson/Rivest. At least that's - the book that my professor took most algorithms from during the "Data - Structures" course... - - Totally public domain. */ - -/* Red/black trees are binary trees in which the edges are colored either red - or black. They have the following properties: - 1. The number of black edges on every path from the root to a leaf is - constant. - 2. No two red edges are adjacent. - Therefore there is an upper bound on the length of every path, it's - O(log n) where n is the number of nodes in the tree. No path can be longer - than 1+2*P where P is the length of the shortest path in the tree. - Useful for the implementation: - 3. If one of the children of a node is NULL, then the other one is red - (if it exists). - - In the implementation, not the edges are colored, but the nodes. The color - interpreted as the color of the edge leading to this node. The color is - meaningless for the root node, but we color the root node black for - convenience. All added nodes are red initially. - - Adding to a red/black tree is rather easy. The right place is searched - with a usual binary tree search. Additionally, whenever a node N is - reached that has two red successors, the successors are colored black and - the node itself colored red. This moves red edges up the tree where they - pose less of a problem once we get to really insert the new node. Changing - N's color to red may violate rule 2, however, so rotations may become - necessary to restore the invariants. Adding a new red leaf may violate - the same rule, so afterwards an additional check is run and the tree - possibly rotated. - - Deleting is hairy. There are mainly two nodes involved: the node to be - deleted (n1), and another node that is to be unchained from the tree (n2). - If n1 has a successor (the node with a smallest key that is larger than - n1), then the successor becomes n2 and its contents are copied into n1, - otherwise n1 becomes n2. - Unchaining a node may violate rule 1: if n2 is black, one subtree is - missing one black edge afterwards. The algorithm must try to move this - error upwards towards the root, so that the subtree that does not have - enough black edges becomes the whole tree. Once that happens, the error - has disappeared. It may not be necessary to go all the way up, since it - is possible that rotations and recoloring can fix the error before that. - - Although the deletion algorithm must walk upwards through the tree, we - do not store parent pointers in the nodes. Instead, delete allocates a - small array of parent pointers and fills it while descending the tree. - Since we know that the length of a path is O(log n), where n is the number - of nodes, this is likely to use less memory. */ - -/* Tree rotations look like this: - A C - / \ / \ - B C A G - / \ / \ --> / \ - D E F G B F - / \ - D E - - In this case, A has been rotated left. This preserves the ordering of the - binary tree. */ - -#include -#include -#include - -typedef struct node_t -{ - /* Callers expect this to be the first element in the structure - do not - move! */ - const void *key; - struct node_t *left; - struct node_t *right; - unsigned int red:1; -} *node; -typedef const struct node_t *const_node; - -#undef DEBUGGING - -#ifdef DEBUGGING - -/* Routines to check tree invariants. */ - -#include - -#define CHECK_TREE(a) check_tree(a) - -static void -check_tree_recurse (node p, int d_sofar, int d_total) -{ - if (p == NULL) - { - assert (d_sofar == d_total); - return; - } - - check_tree_recurse (p->left, d_sofar + (p->left && !p->left->red), d_total); - check_tree_recurse (p->right, d_sofar + (p->right && !p->right->red), d_total); - if (p->left) - assert (!(p->left->red && p->red)); - if (p->right) - assert (!(p->right->red && p->red)); -} - -static void -check_tree (node root) -{ - int cnt = 0; - node p; - if (root == NULL) - return; - root->red = 0; - for(p = root->left; p; p = p->left) - cnt += !p->red; - check_tree_recurse (root, 0, cnt); -} - - -#else - -#define CHECK_TREE(a) - -#endif - -/* Possibly "split" a node with two red successors, and/or fix up two red - edges in a row. ROOTP is a pointer to the lowest node we visited, PARENTP - and GPARENTP pointers to its parent/grandparent. P_R and GP_R contain the - comparison values that determined which way was taken in the tree to reach - ROOTP. MODE is 1 if we need not do the split, but must check for two red - edges between GPARENTP and ROOTP. */ -static void -maybe_split_for_insert (node *rootp, node *parentp, node *gparentp, - int p_r, int gp_r, int mode) -{ - node root = *rootp; - node *rp, *lp; - rp = &(*rootp)->right; - lp = &(*rootp)->left; - - /* See if we have to split this node (both successors red). */ - if (mode == 1 - || ((*rp) != NULL && (*lp) != NULL && (*rp)->red && (*lp)->red)) - { - /* This node becomes red, its successors black. */ - root->red = 1; - if (*rp) - (*rp)->red = 0; - if (*lp) - (*lp)->red = 0; - - /* If the parent of this node is also red, we have to do - rotations. */ - if (parentp != NULL && (*parentp)->red) - { - node gp = *gparentp; - node p = *parentp; - /* There are two main cases: - 1. The edge types (left or right) of the two red edges differ. - 2. Both red edges are of the same type. - There exist two symmetries of each case, so there is a total of - 4 cases. */ - if ((p_r > 0) != (gp_r > 0)) - { - /* Put the child at the top of the tree, with its parent - and grandparent as successors. */ - p->red = 1; - gp->red = 1; - root->red = 0; - if (p_r < 0) - { - /* Child is left of parent. */ - p->left = *rp; - *rp = p; - gp->right = *lp; - *lp = gp; - } - else - { - /* Child is right of parent. */ - p->right = *lp; - *lp = p; - gp->left = *rp; - *rp = gp; - } - *gparentp = root; - } - else - { - *gparentp = *parentp; - /* Parent becomes the top of the tree, grandparent and - child are its successors. */ - p->red = 0; - gp->red = 1; - if (p_r < 0) - { - /* Left edges. */ - gp->left = p->right; - p->right = gp; - } - else - { - /* Right edges. */ - gp->right = p->left; - p->left = gp; - } - } - } - } -} - -/* Find or insert datum into search tree. - KEY is the key to be located, ROOTP is the address of tree root, - COMPAR the ordering function. */ -void * -__tsearch (const void *key, void **vrootp, __compar_fn_t compar) -{ - node q; - node *parentp = NULL, *gparentp = NULL; - node *rootp = (node *) vrootp; - node *nextp; - int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler. */ - - if (rootp == NULL) - return NULL; - - /* This saves some additional tests below. */ - if (*rootp != NULL) - (*rootp)->red = 0; - - CHECK_TREE (*rootp); - - nextp = rootp; - while (*nextp != NULL) - { - node root = *rootp; - r = (*compar) (key, root->key); - if (r == 0) - return root; - - maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0); - /* If that did any rotations, parentp and gparentp are now garbage. - That doesn't matter, because the values they contain are never - used again in that case. */ - - nextp = r < 0 ? &root->left : &root->right; - if (*nextp == NULL) - break; - - gparentp = parentp; - parentp = rootp; - rootp = nextp; - - gp_r = p_r; - p_r = r; - } - - q = (struct node_t *) malloc (sizeof (struct node_t)); - if (q != NULL) - { - *nextp = q; /* link new node to old */ - q->key = key; /* initialize new node */ - q->red = 1; - q->left = q->right = NULL; - } - if (nextp != rootp) - /* There may be two red edges in a row now, which we must avoid by - rotating the tree. */ - maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1); - - return q; -} -weak_alias (__tsearch, tsearch) - - -/* Find datum in search tree. - KEY is the key to be located, ROOTP is the address of tree root, - COMPAR the ordering function. */ -void * -__tfind (key, vrootp, compar) - const void *key; - void *const *vrootp; - __compar_fn_t compar; -{ - node *rootp = (node *) vrootp; - - if (rootp == NULL) - return NULL; - - CHECK_TREE (*rootp); - - while (*rootp != NULL) - { - node root = *rootp; - int r; - - r = (*compar) (key, root->key); - if (r == 0) - return root; - - rootp = r < 0 ? &root->left : &root->right; - } - return NULL; -} -weak_alias (__tfind, tfind) - - -/* Delete node with given key. - KEY is the key to be deleted, ROOTP is the address of the root of tree, - COMPAR the comparison function. */ -void * -__tdelete (const void *key, void **vrootp, __compar_fn_t compar) -{ - node p, q, r, retval; - int cmp; - node *rootp = (node *) vrootp; - node root, unchained; - /* Stack of nodes so we remember the parents without recursion. It's - _very_ unlikely that there are paths longer than 40 nodes. The tree - would need to have around 250.000 nodes. */ - int stacksize = 40; - int sp = 0; - node **nodestack = alloca (sizeof (node *) * stacksize); - - if (rootp == NULL) - return NULL; - p = *rootp; - if (p == NULL) - return NULL; - - CHECK_TREE (p); - - while ((cmp = (*compar) (key, (*rootp)->key)) != 0) - { - if (sp == stacksize) - { - node **newstack; - stacksize += 20; - newstack = alloca (sizeof (node *) * stacksize); - nodestack = memcpy (newstack, nodestack, sp * sizeof (node *)); - } - - nodestack[sp++] = rootp; - p = *rootp; - rootp = ((cmp < 0) - ? &(*rootp)->left - : &(*rootp)->right); - if (*rootp == NULL) - return NULL; - } - - /* This is bogus if the node to be deleted is the root... this routine - really should return an integer with 0 for success, -1 for failure - and errno = ESRCH or something. */ - retval = p; - - /* We don't unchain the node we want to delete. Instead, we overwrite - it with its successor and unchain the successor. If there is no - successor, we really unchain the node to be deleted. */ - - root = *rootp; - - r = root->right; - q = root->left; - - if (q == NULL || r == NULL) - unchained = root; - else - { - node *parent = rootp, *up = &root->right; - for (;;) - { - if (sp == stacksize) - { - node **newstack; - stacksize += 20; - newstack = alloca (sizeof (node *) * stacksize); - nodestack = memcpy (newstack, nodestack, sp * sizeof (node *)); - } - nodestack[sp++] = parent; - parent = up; - if ((*up)->left == NULL) - break; - up = &(*up)->left; - } - unchained = *up; - } - - /* We know that either the left or right successor of UNCHAINED is NULL. - R becomes the other one, it is chained into the parent of UNCHAINED. */ - r = unchained->left; - if (r == NULL) - r = unchained->right; - if (sp == 0) - *rootp = r; - else - { - q = *nodestack[sp-1]; - if (unchained == q->right) - q->right = r; - else - q->left = r; - } - - if (unchained != root) - root->key = unchained->key; - if (!unchained->red) - { - /* Now we lost a black edge, which means that the number of black - edges on every path is no longer constant. We must balance the - tree. */ - /* NODESTACK now contains all parents of R. R is likely to be NULL - in the first iteration. */ - /* NULL nodes are considered black throughout - this is necessary for - correctness. */ - while (sp > 0 && (r == NULL || !r->red)) - { - node *pp = nodestack[sp - 1]; - p = *pp; - /* Two symmetric cases. */ - if (r == p->left) - { - /* Q is R's brother, P is R's parent. The subtree with root - R has one black edge less than the subtree with root Q. */ - q = p->right; - if (q != NULL && q->red) - { - /* If Q is red, we know that P is black. We rotate P left - so that Q becomes the top node in the tree, with P below - it. P is colored red, Q is colored black. - This action does not change the black edge count for any - leaf in the tree, but we will be able to recognize one - of the following situations, which all require that Q - is black. */ - q->red = 0; - p->red = 1; - /* Left rotate p. */ - p->right = q->left; - q->left = p; - *pp = q; - /* Make sure pp is right if the case below tries to use - it. */ - nodestack[sp++] = pp = &q->left; - q = p->right; - } - /* We know that Q can't be NULL here. We also know that Q is - black. */ - if ((q->left == NULL || !q->left->red) - && (q->right == NULL || !q->right->red)) - { - /* Q has two black successors. We can simply color Q red. - The whole subtree with root P is now missing one black - edge. Note that this action can temporarily make the - tree invalid (if P is red). But we will exit the loop - in that case and set P black, which both makes the tree - valid and also makes the black edge count come out - right. If P is black, we are at least one step closer - to the root and we'll try again the next iteration. */ - q->red = 1; - r = p; - } - else - { - /* Q is black, one of Q's successors is red. We can - repair the tree with one operation and will exit the - loop afterwards. */ - if (q->right == NULL || !q->right->red) - { - /* The left one is red. We perform the same action as - in maybe_split_for_insert where two red edges are - adjacent but point in different directions: - Q's left successor (let's call it Q2) becomes the - top of the subtree we are looking at, its parent (Q) - and grandparent (P) become its successors. The former - successors of Q2 are placed below P and Q. - P becomes black, and Q2 gets the color that P had. - This changes the black edge count only for node R and - its successors. */ - node q2 = q->left; - q2->red = p->red; - p->right = q2->left; - q->left = q2->right; - q2->right = q; - q2->left = p; - *pp = q2; - p->red = 0; - } - else - { - /* It's the right one. Rotate P left. P becomes black, - and Q gets the color that P had. Q's right successor - also becomes black. This changes the black edge - count only for node R and its successors. */ - q->red = p->red; - p->red = 0; - - q->right->red = 0; - - /* left rotate p */ - p->right = q->left; - q->left = p; - *pp = q; - } - - /* We're done. */ - sp = 1; - r = NULL; - } - } - else - { - /* Comments: see above. */ - q = p->left; - if (q != NULL && q->red) - { - q->red = 0; - p->red = 1; - p->left = q->right; - q->right = p; - *pp = q; - nodestack[sp++] = pp = &q->right; - q = p->left; - } - if ((q->right == NULL || !q->right->red) - && (q->left == NULL || !q->left->red)) - { - q->red = 1; - r = p; - } - else - { - if (q->left == NULL || !q->left->red) - { - node q2 = q->right; - q2->red = p->red; - p->left = q2->right; - q->right = q2->left; - q2->left = q; - q2->right = p; - *pp = q2; - p->red = 0; - } - else - { - q->red = p->red; - p->red = 0; - q->left->red = 0; - p->left = q->right; - q->right = p; - *pp = q; - } - sp = 1; - r = NULL; - } - } - --sp; - } - if (r != NULL) - r->red = 0; - } - - free (unchained); - return retval; -} -weak_alias (__tdelete, tdelete) - - -/* Walk the nodes of a tree. - ROOT is the root of the tree to be walked, ACTION the function to be - called at each node. LEVEL is the level of ROOT in the whole tree. */ -static void -internal_function -trecurse (const void *vroot, __action_fn_t action, int level) -{ - const_node root = (const_node) vroot; - - if (root->left == NULL && root->right == NULL) - (*action) (root, leaf, level); - else - { - (*action) (root, preorder, level); - if (root->left != NULL) - trecurse (root->left, action, level + 1); - (*action) (root, postorder, level); - if (root->right != NULL) - trecurse (root->right, action, level + 1); - (*action) (root, endorder, level); - } -} - - -/* Walk the nodes of a tree. - ROOT is the root of the tree to be walked, ACTION the function to be - called at each node. */ -void -__twalk (const void *vroot, __action_fn_t action) -{ - const_node root = (const_node) vroot; - - CHECK_TREE (root); - - if (root != NULL && action != NULL) - trecurse (root, action, 0); -} -weak_alias (__twalk, twalk) - - -/* The standardized functions miss an important functionality: the - tree cannot be removed easily. We provide a function to do this. */ -static void -internal_function -tdestroy_recurse (node root, __free_fn_t freefct) -{ - if (root->left != NULL) - tdestroy_recurse (root->left, freefct); - if (root->right != NULL) - tdestroy_recurse (root->right, freefct); - (*freefct) ((void *) root->key); - /* Free the node itself. */ - free (root); -} - -void -__tdestroy (void *vroot, __free_fn_t freefct) -{ - node root = (node) vroot; - - CHECK_TREE (root); - - if (root != NULL) - tdestroy_recurse (root, freefct); -} -weak_alias (__tdestroy, tdestroy) diff --git a/src/system/libroot/posix/musl/Jamfile b/src/system/libroot/posix/musl/Jamfile index ba22757cea..139b40bb5c 100644 --- a/src/system/libroot/posix/musl/Jamfile +++ b/src/system/libroot/posix/musl/Jamfile @@ -9,6 +9,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { : <$(architecture)>posix_musl_math.o <$(architecture)>posix_musl_regex.o + <$(architecture)>posix_musl_search.o <$(architecture)>posix_musl_string.o ; } @@ -20,4 +21,5 @@ for arch in $(TARGET_ARCHS) { } HaikuSubInclude regex ; +HaikuSubInclude search ; HaikuSubInclude string ; diff --git a/src/system/libroot/posix/musl/search/Jamfile b/src/system/libroot/posix/musl/search/Jamfile new file mode 100644 index 0000000000..a70172d45f --- /dev/null +++ b/src/system/libroot/posix/musl/search/Jamfile @@ -0,0 +1,21 @@ +SubDir HAIKU_TOP src system libroot posix musl search ; + +SubDirSysHdrs [ FDirName $(SUBDIR) .. include ] ; +UseHeaders [ FDirName $(SUBDIR) .. internal ] ; + +local architectureObject ; +for architectureObject in [ MultiArchSubDirSetup ] { + on $(architectureObject) { + local architecture = $(TARGET_PACKAGING_ARCH) ; + + MergeObject <$(architecture)>posix_musl_search.o : + hsearch.c + insque.c + lsearch.c + tdelete.c + tfind.c + tsearch.c + twalk.c + ; + } +} diff --git a/src/system/libroot/posix/musl/search/hsearch.c b/src/system/libroot/posix/musl/search/hsearch.c new file mode 100644 index 0000000000..26fa76e407 --- /dev/null +++ b/src/system/libroot/posix/musl/search/hsearch.c @@ -0,0 +1,162 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +/* +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; +}; + +#ifdef __HAIKU__ +struct hsearch_data { + struct __tab *__tab; + unsigned int __unused1; + unsigned int __unused2; +}; +#endif + +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/src/system/libroot/posix/musl/search/insque.c b/src/system/libroot/posix/musl/search/insque.c new file mode 100644 index 0000000000..b7475d84f3 --- /dev/null +++ b/src/system/libroot/posix/musl/search/insque.c @@ -0,0 +1,32 @@ +#include + +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/src/system/libroot/posix/musl/search/lsearch.c b/src/system/libroot/posix/musl/search/lsearch.c new file mode 100644 index 0000000000..5eb5cc2bd5 --- /dev/null +++ b/src/system/libroot/posix/musl/search/lsearch.c @@ -0,0 +1,31 @@ +#include +#include + +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/src/system/libroot/posix/musl/search/tdelete.c b/src/system/libroot/posix/musl/search/tdelete.c new file mode 100644 index 0000000000..646c4fb7b2 --- /dev/null +++ b/src/system/libroot/posix/musl/search/tdelete.c @@ -0,0 +1,53 @@ +#include +#include +#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/src/system/libroot/posix/musl/search/tfind.c b/src/system/libroot/posix/musl/search/tfind.c new file mode 100644 index 0000000000..b07a284b58 --- /dev/null +++ b/src/system/libroot/posix/musl/search/tfind.c @@ -0,0 +1,24 @@ +#include +#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/src/system/libroot/posix/musl/search/tsearch.c b/src/system/libroot/posix/musl/search/tsearch.c new file mode 100644 index 0000000000..004c3fa859 --- /dev/null +++ b/src/system/libroot/posix/musl/search/tsearch.c @@ -0,0 +1,96 @@ +#include +#include +#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

h - old; + } + return rot(p, n, h0key); + 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/src/system/libroot/posix/musl/search/tsearch.h b/src/system/libroot/posix/musl/search/tsearch.h new file mode 100644 index 0000000000..37d11d7354 --- /dev/null +++ b/src/system/libroot/posix/musl/search/tsearch.h @@ -0,0 +1,13 @@ +#include +#include + +/* 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/src/system/libroot/posix/musl/search/twalk.c b/src/system/libroot/posix/musl/search/twalk.c new file mode 100644 index 0000000000..53821cdaf3 --- /dev/null +++ b/src/system/libroot/posix/musl/search/twalk.c @@ -0,0 +1,22 @@ +#include +#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); +}