diff --git a/compat/Makefile.am b/compat/Makefile.am index 20d4186..34f1f06 100644 --- a/compat/Makefile.am +++ b/compat/Makefile.am @@ -1,7 +1,5 @@ AUTOMAKE_OPTIONS = 1.10 foreign subdir-objects -SUBDIRS = sys - EXTRA_DIST = compat.h CLEANFILES = *~ *.core core diff --git a/compat/compat.h b/compat/compat.h index 87ad851..31be05e 100644 --- a/compat/compat.h +++ b/compat/compat.h @@ -29,4 +29,8 @@ size_t strlcpy(char *, const char *, size_t); long long strtonum(const char *, long long, long long, const char **); #endif /* !HAVE_STROTONUM */ +#ifndef HAVE_REALLOCARRAY +void * reallocarray(void *, size_t, size_t); +#endif /* !HAVE_REALLOCARRAY */ + #endif /* __COMPAT_H__ */ diff --git a/compat/reallocarray.c b/compat/reallocarray.c new file mode 100644 index 0000000..a7eade1 --- /dev/null +++ b/compat/reallocarray.c @@ -0,0 +1,44 @@ +/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */ +/* + * Copyright (c) 2008 Otto Moerbeek + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "compat.h" + +#ifndef SIZE_T_MAX +# define SIZE_T_MAX ((size_t)-1) +#endif /* !SIZE_T_MAX */ + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} diff --git a/compat/sys/Makefile.am b/compat/sys/Makefile.am deleted file mode 100644 index 9cafd1e..0000000 --- a/compat/sys/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -AUTOMAKE_OPTIONS = 1.10 foreign subdir-objects - -EXTRA_DIST = tree.h tree.3 - -CLEANFILES = *~ *.core core diff --git a/compat/sys/tree.3 b/compat/sys/tree.3 deleted file mode 100644 index ead02ea..0000000 --- a/compat/sys/tree.3 +++ /dev/null @@ -1,577 +0,0 @@ -.\" $OpenBSD: tree.3,v 1.26 2014/09/08 01:27:55 schwarze Exp $ -.\"/* -.\" * Copyright 2002 Niels Provos -.\" * All rights reserved. -.\" * -.\" * Redistribution and use in source and binary forms, with or without -.\" * modification, are permitted provided that the following conditions -.\" * are met: -.\" * 1. Redistributions of source code must retain the above copyright -.\" * notice, this list of conditions and the following disclaimer. -.\" * 2. Redistributions in binary form must reproduce the above copyright -.\" * notice, this list of conditions and the following disclaimer in the -.\" * documentation and/or other materials provided with the distribution. -.\" * -.\" * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" */ -.Dd $Mdocdate: September 8 2014 $ -.Dt TREE 3 -.Os -.Sh NAME -.Nm SPLAY_PROTOTYPE , -.Nm SPLAY_GENERATE , -.Nm SPLAY_ENTRY , -.Nm SPLAY_HEAD , -.Nm SPLAY_INITIALIZER , -.Nm SPLAY_ROOT , -.Nm SPLAY_EMPTY , -.Nm SPLAY_NEXT , -.Nm SPLAY_MIN , -.Nm SPLAY_MAX , -.Nm SPLAY_FIND , -.Nm SPLAY_LEFT , -.Nm SPLAY_RIGHT , -.Nm SPLAY_FOREACH , -.Nm SPLAY_INIT , -.Nm SPLAY_INSERT , -.Nm SPLAY_REMOVE , -.Nm RB_PROTOTYPE , -.Nm RB_PROTOTYPE_STATIC , -.Nm RB_GENERATE , -.Nm RB_GENERATE_STATIC , -.Nm RB_ENTRY , -.Nm RB_HEAD , -.Nm RB_INITIALIZER , -.Nm RB_ROOT , -.Nm RB_EMPTY , -.Nm RB_NEXT , -.Nm RB_PREV , -.Nm RB_MIN , -.Nm RB_MAX , -.Nm RB_FIND , -.Nm RB_NFIND , -.Nm RB_LEFT , -.Nm RB_RIGHT , -.Nm RB_PARENT , -.Nm RB_FOREACH , -.Nm RB_FOREACH_SAFE , -.Nm RB_FOREACH_REVERSE , -.Nm RB_FOREACH_REVERSE_SAFE , -.Nm RB_INIT , -.Nm RB_INSERT , -.Nm RB_REMOVE -.Nd implementations of splay and red-black trees -.Sh SYNOPSIS -.In sys/tree.h -.Pp -.Fn SPLAY_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP" -.Fn SPLAY_GENERATE "NAME" "TYPE" "FIELD" "CMP" -.Fn SPLAY_ENTRY "TYPE" -.Fn SPLAY_HEAD "HEADNAME" "TYPE" -.Ft "struct TYPE *" -.Fn SPLAY_INITIALIZER "SPLAY_HEAD *head" -.Fn SPLAY_ROOT "SPLAY_HEAD *head" -.Ft "int" -.Fn SPLAY_EMPTY "SPLAY_HEAD *head" -.Ft "struct TYPE *" -.Fn SPLAY_NEXT "NAME" "SPLAY_HEAD *head" "struct TYPE *elm" -.Ft "struct TYPE *" -.Fn SPLAY_MIN "NAME" "SPLAY_HEAD *head" -.Ft "struct TYPE *" -.Fn SPLAY_MAX "NAME" "SPLAY_HEAD *head" -.Ft "struct TYPE *" -.Fn SPLAY_FIND "NAME" "SPLAY_HEAD *head" "struct TYPE *elm" -.Ft "struct TYPE *" -.Fn SPLAY_LEFT "struct TYPE *elm" "SPLAY_ENTRY NAME" -.Ft "struct TYPE *" -.Fn SPLAY_RIGHT "struct TYPE *elm" "SPLAY_ENTRY NAME" -.Fn SPLAY_FOREACH "VARNAME" "NAME" "SPLAY_HEAD *head" -.Ft void -.Fn SPLAY_INIT "SPLAY_HEAD *head" -.Ft "struct TYPE *" -.Fn SPLAY_INSERT "NAME" "SPLAY_HEAD *head" "struct TYPE *elm" -.Ft "struct TYPE *" -.Fn SPLAY_REMOVE "NAME" "SPLAY_HEAD *head" "struct TYPE *elm" -.Pp -.Fn RB_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP" -.Fn RB_PROTOTYPE_STATIC "NAME" "TYPE" "FIELD" "CMP" -.Fn RB_GENERATE "NAME" "TYPE" "FIELD" "CMP" -.Fn RB_GENERATE_STATIC "NAME" "TYPE" "FIELD" "CMP" -.Fn RB_ENTRY "TYPE" -.Fn RB_HEAD "HEADNAME" "TYPE" -.Fn RB_INITIALIZER "RB_HEAD *head" -.Ft "struct TYPE *" -.Fn RB_ROOT "RB_HEAD *head" -.Ft "int" -.Fn RB_EMPTY "RB_HEAD *head" -.Ft "struct TYPE *" -.Fn RB_NEXT "NAME" "RB_HEAD *head" "struct TYPE *elm" -.Ft "struct TYPE *" -.Fn RB_PREV "NAME" "RB_HEAD *head" "struct TYPE *elm" -.Ft "struct TYPE *" -.Fn RB_MIN "NAME" "RB_HEAD *head" -.Ft "struct TYPE *" -.Fn RB_MAX "NAME" "RB_HEAD *head" -.Ft "struct TYPE *" -.Fn RB_FIND "NAME" "RB_HEAD *head" "struct TYPE *elm" -.Ft "struct TYPE *" -.Fn RB_NFIND "NAME" "RB_HEAD *head" "struct TYPE *elm" -.Ft "struct TYPE *" -.Fn RB_LEFT "struct TYPE *elm" "RB_ENTRY NAME" -.Ft "struct TYPE *" -.Fn RB_RIGHT "struct TYPE *elm" "RB_ENTRY NAME" -.Ft "struct TYPE *" -.Fn RB_PARENT "struct TYPE *elm" "RB_ENTRY NAME" -.Fn RB_FOREACH "VARNAME" "NAME" "RB_HEAD *head" -.Fn RB_FOREACH_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME" -.Fn RB_FOREACH_REVERSE "VARNAME" "NAME" "RB_HEAD *head" -.Fn RB_FOREACH_REVERSE_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME" -.Ft void -.Fn RB_INIT "RB_HEAD *head" -.Ft "struct TYPE *" -.Fn RB_INSERT "NAME" "RB_HEAD *head" "struct TYPE *elm" -.Ft "struct TYPE *" -.Fn RB_REMOVE "NAME" "RB_HEAD *head" "struct TYPE *elm" -.Sh DESCRIPTION -These macros define data structures for different types of trees: -splay trees and red-black trees. -.Pp -In the macro definitions, -.Fa TYPE -is the name tag of a user defined structure that must contain a field named -.Fa FIELD , -of type -.Li SPLAY_ENTRY -or -.Li RB_ENTRY . -The argument -.Fa HEADNAME -is the name tag of a user defined structure that must be declared -using the macros -.Fn SPLAY_HEAD -or -.Fn RB_HEAD . -The argument -.Fa NAME -has to be a unique name prefix for every tree that is defined. -.Pp -The function prototypes are declared with -.Li SPLAY_PROTOTYPE , -.Li RB_PROTOTYPE , -or -.Li RB_PROTOTYPE_STATIC . -The function bodies are generated with -.Li SPLAY_GENERATE , -.Li RB_GENERATE , -or -.Li RB_GENERATE_STATIC . -See the examples below for further explanation of how these macros are used. -.Sh SPLAY TREES -A splay tree is a self-organizing data structure. -Every operation on the tree causes a splay to happen. -The splay moves the requested node to the root of the tree and partly -rebalances it. -.Pp -This has the benefit that request locality causes faster lookups as -the requested nodes move to the top of the tree. -On the other hand, every lookup causes memory writes. -.Pp -The Balance Theorem bounds the total access time for m operations -and n inserts on an initially empty tree as O((m + n)lg n). -The amortized cost for a sequence of m accesses to a splay tree is O(lg n). -.Pp -A splay tree is headed by a structure defined by the -.Fn SPLAY_HEAD -macro. -A -.Fa SPLAY_HEAD -structure is declared as follows: -.Bd -literal -offset indent -SPLAY_HEAD(HEADNAME, TYPE) head; -.Ed -.Pp -where -.Fa HEADNAME -is the name of the structure to be defined, and struct -.Fa TYPE -is the type of the elements to be inserted into the tree. -.Pp -The -.Fn SPLAY_ENTRY -macro declares a structure that allows elements to be connected in the tree. -.Pp -In order to use the functions that manipulate the tree structure, -their prototypes need to be declared with the -.Fn SPLAY_PROTOTYPE -macro, -where -.Fa NAME -is a unique identifier for this particular tree. -The -.Fa TYPE -argument is the type of the structure that is being managed -by the tree. -The -.Fa FIELD -argument is the name of the element defined by -.Fn SPLAY_ENTRY . -.Pp -The function bodies are generated with the -.Fn SPLAY_GENERATE -macro. -It takes the same arguments as the -.Fn SPLAY_PROTOTYPE -macro, but should be used only once. -.Pp -Finally, -the -.Fa CMP -argument is the name of a function used to compare trees' nodes -with each other. -The function takes two arguments of type -.Fa "struct TYPE *" . -If the first argument is smaller than the second, the function returns a -value smaller than zero. -If they are equal, the function returns zero. -Otherwise, it should return a value greater than zero. -The compare function defines the order of the tree elements. -.Pp -The -.Fn SPLAY_INIT -macro initializes the tree referenced by -.Fa head . -.Pp -The splay tree can also be initialized statically by using the -.Fn SPLAY_INITIALIZER -macro like this: -.Bd -literal -offset indent -SPLAY_HEAD(HEADNAME, TYPE) head = SPLAY_INITIALIZER(&head); -.Ed -.Pp -The -.Fn SPLAY_INSERT -macro inserts the new element -.Fa elm -into the tree. -Upon success, -.Va NULL -is returned. -If a matching element already exists in the tree, the insertion is -aborted, and a pointer to the existing element is returned. -.Pp -The -.Fn SPLAY_REMOVE -macro removes the element -.Fa elm -from the tree pointed by -.Fa head . -Upon success, a pointer to the removed element is returned. -.Va NULL -is returned if -.Fa elm -is not present in the tree. -.Pp -The -.Fn SPLAY_FIND -macro can be used to find a particular element in the tree. -.Bd -literal -offset indent -struct TYPE find, *res; -find.key = 30; -res = SPLAY_FIND(NAME, &head, &find); -.Ed -.Pp -The -.Fn SPLAY_ROOT , -.Fn SPLAY_MIN , -.Fn SPLAY_MAX , -and -.Fn SPLAY_NEXT -macros can be used to traverse the tree: -.Bd -literal -offset indent -for (np = SPLAY_MIN(NAME, &head); np != NULL; np = SPLAY_NEXT(NAME, &head, np)) -.Ed -.Pp -Or, for simplicity, one can use the -.Fn SPLAY_FOREACH -macro: -.Bd -literal -offset indent -SPLAY_FOREACH(np, NAME, &head) -.Ed -.Pp -The -.Fn SPLAY_EMPTY -macro should be used to check whether a splay tree is empty. -.Sh RED-BLACK TREES -A red-black tree is a binary search tree with the node color as an -extra attribute. -It fulfills a set of conditions: -.Pp -.Bl -enum -compact -offset indent -.It -every search path from the root to a leaf consists of the same number of -black nodes, -.It -each red node (except for the root) has a black parent, -.It -each leaf node is black. -.El -.Pp -Every operation on a red-black tree is bounded as O(lg n). -The maximum height of a red-black tree is 2lg (n+1). -.Pp -A red-black tree is headed by a structure defined by the -.Fn RB_HEAD -macro. -A -.Fa RB_HEAD -structure is declared as follows: -.Bd -literal -offset indent -RB_HEAD(HEADNAME, TYPE) head; -.Ed -.Pp -where -.Fa HEADNAME -is the name of the structure to be defined, and struct -.Fa TYPE -is the type of the elements to be inserted into the tree. -.Pp -The -.Fn RB_ENTRY -macro declares a structure that allows elements to be connected in the tree. -.Pp -In order to use the functions that manipulate the tree structure, -their prototypes need to be declared with the -.Fn RB_PROTOTYPE -or -.Fn RB_PROTOTYPE_STATIC -macros, -where -.Fa NAME -is a unique identifier for this particular tree. -The -.Fa TYPE -argument is the type of the structure that is being managed -by the tree. -The -.Fa FIELD -argument is the name of the element defined by -.Fn RB_ENTRY . -.Pp -The function bodies are generated with the -.Fn RB_GENERATE -or -.Fn RB_GENERATE_STATIC -macros. -These macros take the same arguments as the -.Fn RB_PROTOTYPE -and -.Fn RB_PROTOTYPE_STATIC -macros, but should be used only once. -.Pp -Finally, -the -.Fa CMP -argument is the name of a function used to compare trees' nodes -with each other. -The function takes two arguments of type -.Fa "struct TYPE *" . -If the first argument is smaller than the second, the function returns a -value smaller than zero. -If they are equal, the function returns zero. -Otherwise, it should return a value greater than zero. -The compare function defines the order of the tree elements. -.Pp -The -.Fn RB_INIT -macro initializes the tree referenced by -.Fa head . -.Pp -The red-black tree can also be initialized statically by using the -.Fn RB_INITIALIZER -macro like this: -.Bd -literal -offset indent -RB_HEAD(HEADNAME, TYPE) head = RB_INITIALIZER(&head); -.Ed -.Pp -The -.Fn RB_INSERT -macro inserts the new element -.Fa elm -into the tree. -Upon success, -.Va NULL -is returned. -If a matching element already exists in the tree, the insertion is -aborted, and a pointer to the existing element is returned. -.Pp -The -.Fn RB_REMOVE -macro removes the element -.Fa elm -from the tree pointed by -.Fa head . -.Fn RB_REMOVE -returns -.Fa elm . -.Pp -The -.Fn RB_FIND -and -.Fn RB_NFIND -macros can be used to find a particular element in the tree. -.Fn RB_FIND -finds the node with the same key as -.Fa elm . -.Fn RB_NFIND -finds the first node greater than or equal to the search key. -.Bd -literal -offset indent -struct TYPE find, *res; -find.key = 30; -res = RB_FIND(NAME, &head, &find); -.Ed -.Pp -The -.Fn RB_ROOT , -.Fn RB_MIN , -.Fn RB_MAX , -.Fn RB_NEXT , -and -.Fn RB_PREV -macros can be used to traverse the tree: -.Bd -literal -offset indent -for (np = RB_MIN(NAME, &head); np != NULL; np = RB_NEXT(NAME, &head, np)) -.Ed -.Pp -Or, for simplicity, one can use the -.Fn RB_FOREACH -or -.Fn RB_FOREACH_REVERSE -macros: -.Bd -literal -offset indent -RB_FOREACH(np, NAME, &head) -.Ed -.Pp -The macros -.Fn RB_FOREACH_SAFE -and -.Fn RB_FOREACH_REVERSE_SAFE -traverse the tree referenced by head -in a forward or reverse direction respectively, -assigning each element in turn to np. -However, unlike their unsafe counterparts, -they permit both the removal of np -as well as freeing it from within the loop safely -without interfering with the traversal. -.Pp -The -.Fn RB_EMPTY -macro should be used to check whether a red-black tree is empty. -.Sh EXAMPLES -The following example demonstrates how to declare a red-black tree -holding integers. -Values are inserted into it and the contents of the tree are printed -in order. -Lastly, the internal structure of the tree is printed. -.Bd -literal -offset 3n -#include -#include -#include -#include - -struct node { - RB_ENTRY(node) entry; - int i; -}; - -int -intcmp(struct node *e1, struct node *e2) -{ - return (e1->i < e2->i ? -1 : e1->i > e2->i); -} - -RB_HEAD(inttree, node) head = RB_INITIALIZER(&head); -RB_GENERATE(inttree, node, entry, intcmp) - -int testdata[] = { - 20, 16, 17, 13, 3, 6, 1, 8, 2, 4, 10, 19, 5, 9, 12, 15, 18, - 7, 11, 14 -}; - -void -print_tree(struct node *n) -{ - struct node *left, *right; - - if (n == NULL) { - printf("nil"); - return; - } - left = RB_LEFT(n, entry); - right = RB_RIGHT(n, entry); - if (left == NULL && right == NULL) - printf("%d", n->i); - else { - printf("%d(", n->i); - print_tree(left); - printf(","); - print_tree(right); - printf(")"); - } -} - -int -main() -{ - int i; - struct node *n; - - for (i = 0; i < sizeof(testdata) / sizeof(testdata[0]); i++) { - if ((n = malloc(sizeof(struct node))) == NULL) - err(1, NULL); - n->i = testdata[i]; - RB_INSERT(inttree, &head, n); - } - - RB_FOREACH(n, inttree, &head) { - printf("%d\en", n->i); - } - print_tree(RB_ROOT(&head)); - printf("\en"); - return (0); -} -.Ed -.Sh NOTES -Trying to free a tree in the following way is a common error: -.Bd -literal -offset indent -SPLAY_FOREACH(var, NAME, &head) { - SPLAY_REMOVE(NAME, &head, var); - free(var); -} -free(head); -.Ed -.Pp -Since -.Va var -is free'd, the -.Fn FOREACH -macro refers to a pointer that may have been reallocated already. -Proper code needs a second variable. -.Bd -literal -offset indent -for (var = SPLAY_MIN(NAME, &head); var != NULL; var = nxt) { - nxt = SPLAY_NEXT(NAME, &head, var); - SPLAY_REMOVE(NAME, &head, var); - free(var); -} -.Ed -.Sh AUTHORS -The author of the tree macros is -.An Niels Provos . diff --git a/compat/sys/tree.h b/compat/sys/tree.h deleted file mode 100644 index 80d0f53..0000000 --- a/compat/sys/tree.h +++ /dev/null @@ -1,748 +0,0 @@ -/* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */ -/* - * Copyright 2002 Niels Provos - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SYS_TREE_H_ -#define _SYS_TREE_H_ - -/* - * This file defines data structures for different types of trees: - * splay trees and red-black trees. - * - * A splay tree is a self-organizing data structure. Every operation - * on the tree causes a splay to happen. The splay moves the requested - * node to the root of the tree and partly rebalances it. - * - * This has the benefit that request locality causes faster lookups as - * the requested nodes move to the top of the tree. On the other hand, - * every lookup causes memory writes. - * - * The Balance Theorem bounds the total access time for m operations - * and n inserts on an initially empty tree as O((m + n)lg n). The - * amortized cost for a sequence of m accesses to a splay tree is O(lg n); - * - * A red-black tree is a binary search tree with the node color as an - * extra attribute. It fulfills a set of conditions: - * - every search path from the root to a leaf consists of the - * same number of black nodes, - * - each red node (except for the root) has a black parent, - * - each leaf node is black. - * - * Every operation on a red-black tree is bounded as O(lg n). - * The maximum height of a red-black tree is 2lg (n+1). - */ - -#define SPLAY_HEAD(name, type) \ -struct name { \ - struct type *sph_root; /* root of the tree */ \ -} - -#define SPLAY_INITIALIZER(root) \ - { NULL } - -#define SPLAY_INIT(root) do { \ - (root)->sph_root = NULL; \ -} while (0) - -#define SPLAY_ENTRY(type) \ -struct { \ - struct type *spe_left; /* left element */ \ - struct type *spe_right; /* right element */ \ -} - -#define SPLAY_LEFT(elm, field) (elm)->field.spe_left -#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right -#define SPLAY_ROOT(head) (head)->sph_root -#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) - -/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ -#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_LINKLEFT(head, tmp, field) do { \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_LINKRIGHT(head, tmp, field) do { \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ - SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (0) - -/* Generates prototypes and inline functions */ - -#define SPLAY_PROTOTYPE(name, type, field, cmp) \ -void name##_SPLAY(struct name *, struct type *); \ -void name##_SPLAY_MINMAX(struct name *, int); \ -struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ -struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ - \ -/* Finds the node with the same key as elm */ \ -static __inline struct type * \ -name##_SPLAY_FIND(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) \ - return(NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) \ - return (head->sph_root); \ - return (NULL); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_NEXT(struct name *head, struct type *elm) \ -{ \ - name##_SPLAY(head, elm); \ - if (SPLAY_RIGHT(elm, field) != NULL) { \ - elm = SPLAY_RIGHT(elm, field); \ - while (SPLAY_LEFT(elm, field) != NULL) { \ - elm = SPLAY_LEFT(elm, field); \ - } \ - } else \ - elm = NULL; \ - return (elm); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_MIN_MAX(struct name *head, int val) \ -{ \ - name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ -} - -/* Main splay operation. - * Moves node close to the key of elm to top - */ -#define SPLAY_GENERATE(name, type, field, cmp) \ -struct type * \ -name##_SPLAY_INSERT(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) { \ - SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ - } else { \ - int __comp; \ - name##_SPLAY(head, elm); \ - __comp = (cmp)(elm, (head)->sph_root); \ - if(__comp < 0) { \ - SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ - SPLAY_RIGHT(elm, field) = (head)->sph_root; \ - SPLAY_LEFT((head)->sph_root, field) = NULL; \ - } else if (__comp > 0) { \ - SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT(elm, field) = (head)->sph_root; \ - SPLAY_RIGHT((head)->sph_root, field) = NULL; \ - } else \ - return ((head)->sph_root); \ - } \ - (head)->sph_root = (elm); \ - return (NULL); \ -} \ - \ -struct type * \ -name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *__tmp; \ - if (SPLAY_EMPTY(head)) \ - return (NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) { \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ - } else { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ - name##_SPLAY(head, elm); \ - SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ - } \ - return (elm); \ - } \ - return (NULL); \ -} \ - \ -void \ -name##_SPLAY(struct name *head, struct type *elm) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - int __comp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while ((__comp = (cmp)(elm, (head)->sph_root))) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) > 0){ \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} \ - \ -/* Splay with either the minimum or the maximum element \ - * Used to find minimum or maximum element in tree. \ - */ \ -void name##_SPLAY_MINMAX(struct name *head, int __comp) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while (1) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp > 0) { \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} - -#define SPLAY_NEGINF -1 -#define SPLAY_INF 1 - -#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) -#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) -#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) -#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) -#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) -#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) - -#define SPLAY_FOREACH(x, name, head) \ - for ((x) = SPLAY_MIN(name, head); \ - (x) != NULL; \ - (x) = SPLAY_NEXT(name, head, x)) - -/* Macros that define a red-black tree */ -#define RB_HEAD(name, type) \ -struct name { \ - struct type *rbh_root; /* root of the tree */ \ -} - -#define RB_INITIALIZER(root) \ - { NULL } - -#define RB_INIT(root) do { \ - (root)->rbh_root = NULL; \ -} while (0) - -#define RB_BLACK 0 -#define RB_RED 1 -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} - -#define RB_LEFT(elm, field) (elm)->field.rbe_left -#define RB_RIGHT(elm, field) (elm)->field.rbe_right -#define RB_PARENT(elm, field) (elm)->field.rbe_parent -#define RB_COLOR(elm, field) (elm)->field.rbe_color -#define RB_ROOT(head) (head)->rbh_root -#define RB_EMPTY(head) (RB_ROOT(head) == NULL) - -#define RB_SET(elm, parent, field) do { \ - RB_PARENT(elm, field) = parent; \ - RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ - RB_COLOR(elm, field) = RB_RED; \ -} while (0) - -#define RB_SET_BLACKRED(black, red, field) do { \ - RB_COLOR(black, field) = RB_BLACK; \ - RB_COLOR(red, field) = RB_RED; \ -} while (0) - -#ifndef RB_AUGMENT -#define RB_AUGMENT(x) do {} while (0) -#endif - -#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ - (tmp) = RB_RIGHT(elm, field); \ - if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ - RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_LEFT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ - (tmp) = RB_LEFT(elm, field); \ - if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ - RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_RIGHT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -/* Generates prototypes and inline functions */ -#define RB_PROTOTYPE(name, type, field, cmp) \ - RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) -#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ - RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) -#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ -attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ -attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ -attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ -attr struct type *name##_RB_INSERT(struct name *, struct type *); \ -attr struct type *name##_RB_FIND(struct name *, struct type *); \ -attr struct type *name##_RB_NFIND(struct name *, struct type *); \ -attr struct type *name##_RB_NEXT(struct type *); \ -attr struct type *name##_RB_PREV(struct type *); \ -attr struct type *name##_RB_MINMAX(struct name *, int); \ - \ - -/* Main rb operation. - * Moves node close to the key of elm to top - */ -#define RB_GENERATE(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp,) -#define RB_GENERATE_STATIC(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) -#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ -attr void \ -name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ -{ \ - struct type *parent, *gparent, *tmp; \ - while ((parent = RB_PARENT(elm, field)) && \ - RB_COLOR(parent, field) == RB_RED) { \ - gparent = RB_PARENT(parent, field); \ - if (parent == RB_LEFT(gparent, field)) { \ - tmp = RB_RIGHT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_RIGHT(parent, field) == elm) { \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_RIGHT(head, gparent, tmp, field); \ - } else { \ - tmp = RB_LEFT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_LEFT(parent, field) == elm) { \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_LEFT(head, gparent, tmp, field); \ - } \ - } \ - RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} \ - \ -attr void \ -name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ -{ \ - struct type *tmp; \ - while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ - elm != RB_ROOT(head)) { \ - if (RB_LEFT(parent, field) == elm) { \ - tmp = RB_RIGHT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ - struct type *oleft; \ - if ((oleft = RB_LEFT(tmp, field)))\ - RB_COLOR(oleft, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_RIGHT(head, tmp, oleft, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_RIGHT(tmp, field)) \ - RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } else { \ - tmp = RB_LEFT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ - struct type *oright; \ - if ((oright = RB_RIGHT(tmp, field)))\ - RB_COLOR(oright, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_LEFT(head, tmp, oright, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_LEFT(tmp, field)) \ - RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } \ - } \ - if (elm) \ - RB_COLOR(elm, field) = RB_BLACK; \ -} \ - \ -attr struct type * \ -name##_RB_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *child, *parent, *old = elm; \ - int color; \ - if (RB_LEFT(elm, field) == NULL) \ - child = RB_RIGHT(elm, field); \ - else if (RB_RIGHT(elm, field) == NULL) \ - child = RB_LEFT(elm, field); \ - else { \ - struct type *left; \ - elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field))) \ - elm = left; \ - child = RB_RIGHT(elm, field); \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ - if (RB_PARENT(elm, field) == old) \ - parent = elm; \ - (elm)->field = (old)->field; \ - if (RB_PARENT(old, field)) { \ - if (RB_LEFT(RB_PARENT(old, field), field) == old)\ - RB_LEFT(RB_PARENT(old, field), field) = elm;\ - else \ - RB_RIGHT(RB_PARENT(old, field), field) = elm;\ - RB_AUGMENT(RB_PARENT(old, field)); \ - } else \ - RB_ROOT(head) = elm; \ - RB_PARENT(RB_LEFT(old, field), field) = elm; \ - if (RB_RIGHT(old, field)) \ - RB_PARENT(RB_RIGHT(old, field), field) = elm; \ - if (parent) { \ - left = parent; \ - do { \ - RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field))); \ - } \ - goto color; \ - } \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ -color: \ - if (color == RB_BLACK) \ - name##_RB_REMOVE_COLOR(head, parent, child); \ - return (old); \ -} \ - \ -/* Inserts a node into the RB tree */ \ -attr struct type * \ -name##_RB_INSERT(struct name *head, struct type *elm) \ -{ \ - struct type *tmp; \ - struct type *parent = NULL; \ - int comp = 0; \ - tmp = RB_ROOT(head); \ - while (tmp) { \ - parent = tmp; \ - comp = (cmp)(elm, parent); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - RB_SET(elm, parent, field); \ - if (parent != NULL) { \ - if (comp < 0) \ - RB_LEFT(parent, field) = elm; \ - else \ - RB_RIGHT(parent, field) = elm; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = elm; \ - name##_RB_INSERT_COLOR(head, elm); \ - return (NULL); \ -} \ - \ -/* Finds the node with the same key as elm */ \ -attr struct type * \ -name##_RB_FIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (NULL); \ -} \ - \ -/* Finds the first node greater than or equal to the search key */ \ -attr struct type * \ -name##_RB_NFIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *res = NULL; \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) { \ - res = tmp; \ - tmp = RB_LEFT(tmp, field); \ - } \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (res); \ -} \ - \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_NEXT(struct type *elm) \ -{ \ - if (RB_RIGHT(elm, field)) { \ - elm = RB_RIGHT(elm, field); \ - while (RB_LEFT(elm, field)) \ - elm = RB_LEFT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} \ - \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_PREV(struct type *elm) \ -{ \ - if (RB_LEFT(elm, field)) { \ - elm = RB_LEFT(elm, field); \ - while (RB_RIGHT(elm, field)) \ - elm = RB_RIGHT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} \ - \ -attr struct type * \ -name##_RB_MINMAX(struct name *head, int val) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *parent = NULL; \ - while (tmp) { \ - parent = tmp; \ - if (val < 0) \ - tmp = RB_LEFT(tmp, field); \ - else \ - tmp = RB_RIGHT(tmp, field); \ - } \ - return (parent); \ -} - -#define RB_NEGINF -1 -#define RB_INF 1 - -#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) -#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) -#define RB_FIND(name, x, y) name##_RB_FIND(x, y) -#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) -#define RB_NEXT(name, x, y) name##_RB_NEXT(y) -#define RB_PREV(name, x, y) name##_RB_PREV(y) -#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) -#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) - -#define RB_FOREACH(x, name, head) \ - for ((x) = RB_MIN(name, head); \ - (x) != NULL; \ - (x) = name##_RB_NEXT(x)) - -#define RB_FOREACH_SAFE(x, name, head, y) \ - for ((x) = RB_MIN(name, head); \ - ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \ - (x) = (y)) - -#define RB_FOREACH_REVERSE(x, name, head) \ - for ((x) = RB_MAX(name, head); \ - (x) != NULL; \ - (x) = name##_RB_PREV(x)) - -#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ - for ((x) = RB_MAX(name, head); \ - ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \ - (x) = (y)) - -#endif /* _SYS_TREE_H_ */ diff --git a/configure.ac b/configure.ac index 31e671b..94a0736 100644 --- a/configure.ac +++ b/configure.ac @@ -248,6 +248,7 @@ AC_CHECK_FUNCS([ \ AC_REPLACE_FUNCS([ \ getopt \ + reallocarray \ strlcat \ strlcpy \ strtonum \ @@ -285,7 +286,6 @@ AC_CONFIG_FILES([ Makefile build-aux/Makefile compat/Makefile - compat/sys/Makefile doc/Makefile doc/ezstream-file.sh.1.in doc/ezstream.1.in diff --git a/src/ezstream.c b/src/ezstream.c index 3be3d33..4035c0d 100644 --- a/src/ezstream.c +++ b/src/ezstream.c @@ -994,7 +994,6 @@ ez_shutdown(int exitval) shout_shutdown(); playlist_shutdown(); freeConfig(pezConfig); - xalloc_shutdown(); log_exit(); return (exitval); @@ -1022,11 +1021,6 @@ main(int argc, char *argv[]) return (ret); log_init(); -#ifdef XALLOC_DEBUG - xalloc_initialize_debug(2, NULL); -#else - xalloc_initialize(); -#endif /* XALLOC_DEBUG */ playlist_init(); shout_init(); diff --git a/src/metadata.c b/src/metadata.c index c0870b1..93c74fc 100644 --- a/src/metadata.c +++ b/src/metadata.c @@ -330,7 +330,7 @@ metadata_normalize_string(char **s) tmpstr[strlen(tmpstr) - 1] = '\0'; xfree(str); - *s = xrealloc(tmpstr, strlen(tmpstr) + 1, sizeof (char)); + *s = xreallocarray(tmpstr, strlen(tmpstr) + 1, sizeof(char)); } metadata_t * diff --git a/src/playlist.c b/src/playlist.c index 845fc95..7014fab 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -70,7 +70,7 @@ playlist_add(playlist_t *pl, const char *entry) if (pl->size / sizeof(char *) <= num) { size_t i; - pl->list = xrealloc(pl->list, 2UL, pl->size); + pl->list = xreallocarray(pl->list, 2UL, pl->size); pl->size = 2 * pl->size; for (i = num; i < pl->size / sizeof(char *); i++) diff --git a/src/xalloc.c b/src/xalloc.c index 644f108..a2de1be 100644 --- a/src/xalloc.c +++ b/src/xalloc.c @@ -18,630 +18,75 @@ # include "config.h" #endif -#include "ezstream.h" +#include "compat.h" +#include +#include + +#include "log.h" #include "xalloc.h" -#ifndef SIZE_T_MAX -# define SIZE_T_MAX ((size_t)-1) -#endif -#ifndef va_copy -# define va_copy(d, s) (d) = (s) -#endif -#define XALLOC_DBGLVL_MAX 2 - -#if defined(XALLOC_DEBUG) && defined(XALLOC_SILENT) -# undef XALLOC_SILENT -#endif /* XALLOC_DEBUG && XALLOC_SILENT */ - -#ifdef XALLOC_DEBUG -# include - -int _memory_cmp(void *, void *); - -struct memory { - RB_ENTRY(memory) entry; - void *ptr; - unsigned int id; - size_t size; - const char *allocated_by; - unsigned int allocated_in_line; - const char *reallocated_by; - unsigned int reallocated_in_line; - const char *freed_by; - unsigned int freed_in_line; -}; -RB_HEAD(memory_tree, memory) memory_tree_head = RB_INITIALIZER(&memory_tree_head); -RB_PROTOTYPE(memory_tree, memory, entry, _memory_cmp) - -void _memory_free(struct memory **); -#endif /* XALLOC_DEBUG */ - -void _xalloc_warn(const char *, ...); -void _xalloc_error(int, const char *, ...); -void _xalloc_fatal(const char *, ...); -void _xalloc_debug_printf(unsigned int, const char *, ...); -#ifdef XALLOC_WITH_XASPRINTF -int _xalloc_vasprintf(char **, const char *, va_list, size_t *); -#endif /* XALLOC_WITH_XASPRINTF */ - -static unsigned int debug_level = 0; -static FILE *debug_output = NULL; -#ifdef XALLOC_DEBUG -static unsigned int xalloc_next_id = 0; -#endif -static int xalloc_initialized = 0; -static size_t xalloc_allocated; -static size_t xalloc_total; -static size_t xalloc_peak; -static size_t xalloc_freed; -static void * (*real_malloc)(size_t) = NULL; -static void * (*real_calloc)(size_t, size_t) = NULL; -static void * (*real_realloc)(void *, size_t) = NULL; -static void (*real_free)(void *) = NULL; -static const char *unknown_file = ""; - -#ifdef XALLOC_DEBUG -RB_GENERATE(memory_tree, memory, entry, _memory_cmp) - -int -_memory_cmp(void *arg_a, void *arg_b) -{ - struct memory *a = (struct memory *)arg_a; - struct memory *b = (struct memory *)arg_b; - - if (a->ptr < b->ptr) - return (-1); - else if (a->ptr > b->ptr) - return (1); - return (0); -} - -void -_memory_free(struct memory **mem_p) -{ - struct memory *mem = *mem_p; - - if (mem->allocated_by != NULL) - mem->allocated_by = NULL; - if (mem->reallocated_by != NULL) - mem->reallocated_by = NULL; - if (mem->freed_by != NULL) - mem->freed_by = NULL; - real_free(mem); - *mem_p = NULL; -} -#endif /* XALLOC_DEBUG */ - -void -_xalloc_warn(const char *fmt, ...) -{ - va_list ap; - - if (debug_output == NULL) - debug_output = XALLOC_DEFAULT_OUTPUT; - - va_start(ap, fmt); -#ifndef XALLOC_SILENT - vfprintf(debug_output, fmt, ap); - fflush(debug_output); -#endif /* !XALLOC_SILENT */ - va_end(ap); -} - -void -_xalloc_error(int errnum, const char *fmt, ...) -{ - va_list ap; - - if (debug_output == NULL) - debug_output = XALLOC_DEFAULT_OUTPUT; - - va_start(ap, fmt); -#ifndef XALLOC_SILENT - vfprintf(debug_output, fmt, ap); - if (errnum > 0) - fprintf(debug_output, ": %s\n", strerror(errnum)); - fflush(debug_output); -#endif /* !XALLOC_SILENT */ - va_end(ap); - - exit(1); -} - -void -_xalloc_fatal(const char *fmt, ...) -{ - va_list ap; - - if (debug_output == NULL) - debug_output = XALLOC_DEFAULT_OUTPUT; - - va_start(ap, fmt); -#ifndef XALLOC_SILENT - vfprintf(debug_output, fmt, ap); - fflush(debug_output); -#endif /* !XALLOC_SILENT */ - va_end(ap); - - abort(); -} - -void -_xalloc_debug_printf(unsigned int level, const char *fmt, ...) -{ - va_list ap; - - if (level > debug_level) - return; - - va_start(ap, fmt); -#ifdef XALLOC_DEBUG - vfprintf(debug_output, fmt, ap); - fflush(debug_output); -#endif /* XALLOC_DEBUG */ - va_end(ap); -} - -#ifdef XALLOC_WITH_XASPRINTF -int -_xalloc_vasprintf(char **str_p, const char *fmt, va_list ap, size_t *strsiz) -{ - int ret = -1; - va_list ap_local; - - *str_p = NULL; - - va_copy(ap_local, ap); - *strsiz = vsnprintf(NULL, (size_t)0, fmt, ap_local) + 1; - va_end(ap_local); -#ifdef HAVE_ASPRINTF - if ((ret = vasprintf(str_p, fmt, ap)) == -1) - *str_p = NULL; -#else - if ((*str_p = real_calloc(*strsiz, sizeof(char))) == NULL) - return (-1); - ret = vsnprintf(*str_p, *strsiz, fmt, ap); -#endif /* HAVE_ASPRINTF */ - - return (ret); -} -#endif /* XALLOC_WITH_XASPRINTF */ - -void -xalloc_initialize_debug(unsigned int level, FILE *output) -{ - if (xalloc_initialized) - _xalloc_fatal("XALLOC: xalloc_initialize(): Xalloc library already initialized\n"); - - if ((debug_level = level) > XALLOC_DBGLVL_MAX) - debug_level = XALLOC_DBGLVL_MAX; - if (output == NULL) - debug_output = XALLOC_DEFAULT_OUTPUT; - else - debug_output = output; - - real_malloc = malloc; - real_calloc = calloc; - real_realloc = realloc; - real_free = free; - xalloc_allocated = 0; - xalloc_total = 0; - xalloc_peak = 0; - xalloc_freed = 0; - - xalloc_initialized = 1; -} - -void -xalloc_set_functions(void *(*malloc_func)(size_t), - void *(*calloc_func)(size_t, size_t), - void *(*realloc_func)(void *, size_t), - void (*free_func)(void *)) -{ - if (!xalloc_initialized) - _xalloc_fatal("XALLOC: xalloc_set_functions(): Xalloc library not initialized\n"); - - if (malloc_func == NULL || - calloc_func == NULL || - realloc_func == NULL) - _xalloc_fatal("XALLOC: xalloc_set_functions(): Bad argument(s)\n"); - - real_malloc = malloc_func; - real_calloc = calloc_func; - real_realloc = realloc_func; - real_free = free_func; -} - -void -xalloc_shutdown(void) -{ - if (!xalloc_initialized) - _xalloc_fatal("XALLOC: xalloc_shutdown(): Xalloc library not initialized\n"); - -#ifdef XALLOC_DEBUG - if (debug_level > 0) { - struct memory *mem, *mem_next; - size_t leaked_bytes = 0; - - for (mem = RB_MIN(memory_tree, &memory_tree_head); - mem != NULL; - mem = mem_next) { - mem_next = RB_NEXT(memory_tree, &memory_tree_head, mem); - RB_REMOVE(memory_tree, &memory_tree_head, mem); - - if (mem->freed_by == NULL) { - _xalloc_debug_printf(1, "XALLOC: MEMORY LEAK (%p:%u): allocated in %s:%u, ", - mem->ptr, - mem->id, - mem->allocated_by, - mem->allocated_in_line); - if (mem->reallocated_by != NULL) - _xalloc_debug_printf(1, "last reallocated in %s:%u, ", - mem->reallocated_by, - mem->reallocated_in_line); - _xalloc_debug_printf(1, "leaks %lu bytes\n", - (unsigned long)mem->size); - leaked_bytes += mem->size; - real_free(mem->ptr); - } - - _memory_free(&mem); - } - - if (leaked_bytes != xalloc_allocated) - _xalloc_fatal("XALLOC: Internal error: xalloc_shutdown(): leaked_bytes(%lu) != xalloc_allocated(%lu)\n", - (unsigned long)leaked_bytes, - (unsigned long)xalloc_allocated); - - _xalloc_debug_printf(1, "XALLOC: STATS: leaked: %lu bytes, peak allocation: %lu bytes (freed/total: %lu/%lu bytes)\n", - (unsigned long)xalloc_allocated, - (unsigned long)xalloc_peak, - (unsigned long)xalloc_freed, - (unsigned long)xalloc_total); - } -#endif /* XALLOC_DEBUG */ - - xalloc_initialized = 0; -} - void * xmalloc_c(size_t size, const char *file, unsigned int line) { - void *ret; + void *ret = malloc(size); - if (!xalloc_initialized) - _xalloc_fatal("XALLOC: xmalloc(): Xalloc library not initialized\n"); - - if (size == 0) - _xalloc_fatal("XALLOC: xmalloc(): %s:%u: Zero size\n", - file ? file : unknown_file, line); - - if ((ret = real_malloc(size)) == NULL) - _xalloc_error(errno, "XALLOC: xmalloc(): %s:%u: Allocating %lu bytes", - file ? file : unknown_file, line, - (unsigned long)(size)); - -#ifdef XALLOC_DEBUG - if (debug_level > 0) { - struct memory *mem, *mem_exists; - - if ((mem = real_calloc(1, sizeof(struct memory))) == NULL) - _xalloc_error(errno, "XALLOC: Internal error"); - mem->ptr = ret; - mem->size = size; - if (file) - mem->allocated_by = file; - else - mem->allocated_by = unknown_file; - mem->allocated_in_line = line; - mem->id = ++xalloc_next_id; - if ((mem_exists = RB_INSERT(memory_tree, &memory_tree_head, mem)) != NULL) { - /* Freed pointer is being reused: */ - if (mem_exists->id != 0) - _xalloc_fatal("XALLOC: Internal error: Assertion (mem_exists->id == 0) in %s:%u failed!\n", - __FILE__, __LINE__); - RB_REMOVE(memory_tree, &memory_tree_head, mem_exists); - _memory_free(&mem_exists); - RB_INSERT(memory_tree, &memory_tree_head, mem); - } - xalloc_allocated += size; - xalloc_total += size; - if (xalloc_allocated > xalloc_peak) - xalloc_peak = xalloc_allocated; + if (NULL == ret) { + log_alert("%s[%u]: cannot allocate %zu bytes", + file, line, size); + exit(1); } -#endif /* XALLOC_DEBUG */ return (ret); } void * -xcalloc_c(size_t nmemb, size_t size, int may_fail, - const char *file, unsigned int line) +xcalloc_c(size_t nmemb, size_t size, const char *file, unsigned int line) { - void *ret; + void *ret = calloc(nmemb, size); - if (!xalloc_initialized) - _xalloc_fatal("XALLOC: xcalloc(): Xalloc library not initialized\n"); - - if (nmemb == 0 || size == 0) - _xalloc_fatal("XALLOC: xcalloc(): %s:%u: Zero size\n", - file ? file : unknown_file, line); - - if (SIZE_T_MAX / nmemb < size) - _xalloc_fatal("XALLOC: xcalloc(): %s:%u: Integer overflow (nmemb * size > SIZE_T_MAX)\n", - file ? file : unknown_file, line); - - if ((ret = real_calloc(nmemb, size)) == NULL && may_fail == 0) - _xalloc_error(errno, "XALLOC: xcalloc(): %s:%u: Allocating %lu bytes", - file ? file : unknown_file, line, - (unsigned long)(nmemb * size)); - -#ifdef XALLOC_DEBUG - if (ret != NULL && debug_level > 0) { - struct memory *mem, *mem_exists; - - if ((mem = real_calloc(1, sizeof(struct memory))) == NULL) - _xalloc_error(errno, "XALLOC: Internal error"); - mem->ptr = ret; - mem->size = nmemb * size; - if (file) - mem->allocated_by = file; - else - mem->allocated_by = unknown_file; - mem->allocated_in_line = line; - mem->id = ++xalloc_next_id; - if ((mem_exists = RB_INSERT(memory_tree, &memory_tree_head, mem)) != NULL) { - /* Freed pointer is being reused: */ - if (mem_exists->id != 0) - _xalloc_fatal("XALLOC: Internal error: Assertion (mem_exists->id == 0) in %s:%u failed!\n", - __FILE__, __LINE__); - RB_REMOVE(memory_tree, &memory_tree_head, mem_exists); - _memory_free(&mem_exists); - RB_INSERT(memory_tree, &memory_tree_head, mem); - } - xalloc_allocated += nmemb * size; - xalloc_total += nmemb * size; - if (xalloc_allocated > xalloc_peak) - xalloc_peak = xalloc_allocated; + if (NULL == ret) { + log_alert("%s[%u]: cannot allocate %zu * %zu bytes", + file, line, nmemb, size); + exit(1); } -#endif /* XALLOC_DEBUG */ return (ret); } void * -xrealloc_c(void *ptr, size_t nmemb, size_t size, - const char *file, unsigned int line) +xreallocarray_c(void *ptr, size_t nmemb, size_t size, const char *file, + unsigned int line) { - void *ret; - size_t nsiz = nmemb * size; -#ifdef XALLOC_DEBUG - struct memory *mem = NULL; -#endif /* XALLOC_DEBUG */ + void *ret = reallocarray(ptr, nmemb, size); - if (!xalloc_initialized) - _xalloc_fatal("XALLOC: xrealloc(): Xalloc library not initialized\n"); - - if (nmemb == 0 || size == 0) - _xalloc_fatal("XALLOC: xrealloc(): %s:%u: Zero size\n", - file ? file : unknown_file, line); - - if (SIZE_T_MAX / nmemb < size) - _xalloc_fatal("XALLOC: xrealloc(): %s:%u: Integer overflow (nmemb * size > SIZE_T_MAX)\n", - file ? file : unknown_file, line); - - if (ptr == NULL) { - ret = real_malloc(nsiz); -#ifdef XALLOC_DEBUG - if (debug_level > 0) { - if ((mem = real_calloc(1, sizeof(struct memory))) == NULL) - _xalloc_error(errno, "XALLOC: Internal error"); - mem->ptr = ret; - mem->id = ++xalloc_next_id; - if (file) - mem->allocated_by = file; - else - mem->allocated_by = unknown_file; - mem->allocated_in_line = line; - } -#endif /* XALLOC_DEBUG */ - } else { -#ifdef XALLOC_DEBUG - struct memory find_mem; - - if (debug_level > 0) { - find_mem.ptr = ptr; - if ((mem = RB_FIND(memory_tree, &memory_tree_head, &find_mem)) == NULL) - _xalloc_fatal("XALLOC: xrealloc(): %s:%u: Junk pointer %p not accounted for\n", - file ? file : unknown_file, - line, ptr); - RB_REMOVE(memory_tree, &memory_tree_head, mem); - } -#endif /* XALLOC_DEBUG */ - ret = real_realloc(ptr, nsiz); -#ifdef XALLOC_DEBUG - if (debug_level > 0) { - mem->ptr = ret; - if (file) - mem->reallocated_by = file; - else - mem->reallocated_by = unknown_file; - mem->reallocated_in_line = line; - } -#endif /* XALLOC_DEBUG */ + if (NULL == ret) { + log_alert("%s[%u]: cannot allocate %zu * %zu bytes", + file, line, nmemb, size); + exit(1); } - if (ret == NULL) - _xalloc_error(errno, "XALLOC: xrealloc(): %s:%u: (Re)allocating %lu bytes", - file ? file : unknown_file, line, - (unsigned long)(nmemb * size)); - -#ifdef XALLOC_DEBUG - if (debug_level > 0) { - struct memory *mem_exists; - ssize_t diff = (ssize_t)(nsiz - mem->size); - - xalloc_allocated += diff; - if (diff < 0) - xalloc_freed += -diff; - else - xalloc_total += diff; - if (xalloc_allocated > xalloc_peak) - xalloc_peak = xalloc_allocated; - mem->size = nsiz; - if ((mem_exists = RB_INSERT(memory_tree, &memory_tree_head, mem)) != NULL) { - /* Freed pointer is being reused: */ - if (mem_exists->id != 0) - _xalloc_fatal("XALLOC: Internal error: Assertion (mem_exists->id == 0) in %s:%u failed!\n", - __FILE__, __LINE__); - RB_REMOVE(memory_tree, &memory_tree_head, mem_exists); - _memory_free(&mem_exists); - RB_INSERT(memory_tree, &memory_tree_head, mem); - } - } -#endif /* XALLOC_DEBUG */ - return (ret); } char * xstrdup_c(const char *str, const char *file, unsigned int line) { - size_t len; - char *nstr; + char *ret = strdup(str); - if (!xalloc_initialized) - _xalloc_fatal("XALLOC: xstrdup(): Xalloc library not initialized\n"); - - len = strlen(str) + 1; - if ((nstr = xcalloc_c(len, sizeof(char), 0, file, line)) == NULL) - _xalloc_error(errno, "XALLOC: xstrdup(): %s:%u: Allocating %lu bytes: %s\n", - file ? file : unknown_file, line, - (unsigned long)(len)); - memcpy(nstr, str, len); - return (nstr); -} - -void -xfree_c(void **ptr_p, const char *file, unsigned int line) -{ - if (!xalloc_initialized) - _xalloc_fatal("XALLOC: xfree(): Xalloc library not initialized\n"); - - if (ptr_p == NULL) - _xalloc_fatal("XALLOC: xfree(): Bad argument(s)\n"); - - if (*ptr_p == NULL) { - _xalloc_warn("XALLOC: xfree(): Warning: %s:%u: Freeing NULL pointer\n", - file ? file : unknown_file, line); - return; + if (NULL == ret) { + log_error("%s[%u]: cannot allocate %zu bytes", + file, line, strlen(str) + 1); + exit(1); } -#ifdef XALLOC_DEBUG - if (debug_level > 0) { - struct memory *mem = NULL, find_mem; - - find_mem.ptr = *ptr_p; - if ((mem = RB_FIND(memory_tree, &memory_tree_head, &find_mem)) == NULL) - _xalloc_fatal("XALLOC: xfree(): %s:%u: Junk pointer %p not accounted for\n", - file ? file : unknown_file, line, - *ptr_p); - - if (mem->freed_by != NULL && mem->id == 0) { - _xalloc_debug_printf(2, "XALLOC: DOUBLE FREE of pointer %p in %s:%u: allocated in %s:%u, ", - mem->ptr, - file ? file : unknown_file, line, - mem->allocated_by, - mem->allocated_in_line); - if (mem->reallocated_by != NULL) - _xalloc_debug_printf(2, "last reallocated in %s:%u, ", - mem->reallocated_by, - mem->reallocated_in_line); - _xalloc_debug_printf(2, "already freed in %s:%u\n", - mem->freed_by, - mem->freed_in_line); - abort(); - } - - xalloc_freed += mem->size; - xalloc_allocated -= mem->size; - mem->id = 0; - mem->size = 0; - if (debug_level > 1) { - if (file) - mem->freed_by = file; - else - mem->freed_by = unknown_file; - mem->freed_in_line = line; - } else { - RB_REMOVE(memory_tree, &memory_tree_head, mem); - _memory_free(&mem); - } - } -#endif /* XALLOC_DEBUG */ - - real_free(*ptr_p); -#ifdef XALLOC_DEBUG - if (debug_level <= 1) -#endif /* XALLOC_DEBUG */ - { - *ptr_p = NULL; - } -} - -#ifdef XALLOC_WITH_XASPRINTF -int -xasprintf_c(const char *file, unsigned int line, - char **str_p, const char *fmt, ...) -{ - int ret; - va_list ap; - size_t strsiz = 0; - - if (!xalloc_initialized) - _xalloc_fatal("XALLOC: xasprintf(): Xalloc library not initialized\n"); - - if (str_p == NULL || fmt == NULL) - _xalloc_fatal("XALLOC: xasprintf(): Bad argument(s)\n"); - - va_start(ap, fmt); - ret = _xalloc_vasprintf(str_p, fmt, ap, &strsiz); - va_end(ap); - if (ret == -1) - _xalloc_error(errno, "XALLOC: xasprintf(): %s:%u: Allocating %lu bytes", - file ? file : unknown_file, line, strsiz); - -# ifdef XALLOC_DEBUG - if (debug_level > 0) { - struct memory *mem, *mem_exists; - - if ((mem = real_calloc(1, sizeof(struct memory))) == NULL) - _xalloc_error(errno, "XALLOC: Internal error"); - mem->ptr = *str_p; - mem->size = strsiz; - if (file) - mem->allocated_by = file; - else - mem->allocated_by = unknown_file; - mem->allocated_in_line = line; - mem->id = ++xalloc_next_id; - if ((mem_exists = RB_INSERT(memory_tree, &memory_tree_head, mem)) != NULL) { - /* Freed pointer is being reused: */ - if (mem_exists->id != 0) - _xalloc_fatal("XALLOC: Internal error: Assertion (mem_exists->id == 0) in %s:%u failed!\n", - __FILE__, __LINE__); - RB_REMOVE(memory_tree, &memory_tree_head, mem_exists); - _memory_free(&mem_exists); - RB_INSERT(memory_tree, &memory_tree_head, mem); - } - xalloc_allocated += strsiz; - xalloc_total += strsiz; - if (xalloc_allocated > xalloc_peak) - xalloc_peak = xalloc_allocated; - } -# endif /* XALLOC_DEBUG */ - return (ret); } -#endif /* XALLOC_WITH_XASPRINTF */ + +void +xfree_c(void *ptr, const char *file, unsigned int line) +{ + (void)file; + (void)line; + free(ptr); +} diff --git a/src/xalloc.h b/src/xalloc.h index 014c350..b86d243 100644 --- a/src/xalloc.h +++ b/src/xalloc.h @@ -1,12 +1,5 @@ /* - * libxalloc - Portable memory allocation wrapper library, with extensive - * error checking, debugging facilities and hooks for 3rd party - * memory allocation functions. - * This library also detects and prevents double-free errors, - * and ensures that out-of-memory issues always cause the - * application to exit. - * - * Copyright (C) 2007 Moritz Grimm + * Copyright (C) 2015 Moritz Grimm * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,91 +17,16 @@ #ifndef __XALLOC_H__ #define __XALLOC_H__ -/* - * Define XALLOC_DEBUG to compile the debugging features. Doing so will make - * this library more expensive in every case, but not change its (visible) - * behavior unless the debugging level is set > 0. The debugging levels are: - * 0: disable debugging - * 1: enable most debugging features - * 2: additionally enable double-free checking - * (Warning: This requires libxalloc to keep track of all allocations - * and frees, which means that memory usage may increase a lot - * over time!) - * - * Define XALLOC_SILENT to suppress all messages, which makes libxalloc - * abort() and exit() silently. - * - * Define XALLOC_WITH_XASPRINTF to expose the xasprintf() interface. Doing - * so will require libxalloc to be compiled with a compiler that supports C99 - * variadic macros, and work only on systems with vasprintf() or vsnprintf(), - * and MS Windows. Note that doing so constitutes an incompatible ABI change! - * - * Note that none of the x*_c() functions should be used directly, unless it - * is ensured that /file/ is a const char * to a real string constant. - */ -/* #define XALLOC_DEBUG 1 */ -/* #define XALLOC_SILENT 1 */ -/* #define XALLOC_WITH_XASPRINTF 1 */ +#define xmalloc(s) xmalloc_c(s, __FILE__, __LINE__) +#define xcalloc(n, s) xcalloc_c(n, s, __FILE__, __LINE__) +#define xreallocarray(p, n, s) xreallocarray_c(p, n, s, __FILE__, __LINE__) +#define xstrdup(str) xstrdup_c(str, __FILE__, __LINE__) +#define xfree(p) xfree_c(p, __FILE__, __LINE__) -/* The default output stream for messages: */ -#define XALLOC_DEFAULT_OUTPUT stderr - - -/* - * Library initialization and shutdown. - */ - -#define xalloc_initialize() \ - xalloc_initialize_debug(0, NULL) -void xalloc_initialize_debug(unsigned int /* level */, - FILE * /* output stream */); - -void xalloc_set_functions(void *(*)(size_t) /* malloc function */, - void *(*)(size_t, size_t) /* calloc function */, - void *(*)(void *, size_t) /* realloc function */, - void (*)(void *) /* free function */); - -/* Memory leak checks happen during shutdown! */ -void xalloc_shutdown(void); - - -/* - * Memory management functions. - * Note that xrealloc() has calloc() semantics, to detect and prevent integer - * overflows. - */ - -#define xmalloc(s) \ - xmalloc_c(s, __FILE__, __LINE__) -void * xmalloc_c(size_t /* size */, - const char * /* file */, unsigned int /* line */); - -#define xcalloc(n, s) \ - xcalloc_c(n, s, 0, __FILE__, __LINE__) -void * xcalloc_c(size_t /* nmemb */, size_t /* size */, int /* may fail */, - const char * /* file */, unsigned int /* line */); - -#define xrealloc(p, n, s) \ - xrealloc_c(p, n, s, __FILE__, __LINE__) -void * xrealloc_c(void *, size_t /* nmemb */, size_t /* size */, - const char * /* file */, unsigned int /* line */); - -#define xstrdup(s) \ - xstrdup_c(s, __FILE__, __LINE__) -char * xstrdup_c(const char *, - const char * /* file */, unsigned int /* line */); - -#define xfree(p) \ - xfree_c((void *)&(p), __FILE__, __LINE__) -void xfree_c(void **, - const char * /* file */, unsigned int /* line */); - -#ifdef XALLOC_WITH_XASPRINTF -# define xasprintf(s, f, ...) \ - xasprintf_c(__FILE__, __LINE__, s, f, __VA_ARGS__) -int xasprintf_c(const char * /* file */, unsigned int /* line */, - char ** /* string pointer */, const char * /* format */, - ...); -#endif /* XALLOC_WITH_XASPRINTF */ +void * xmalloc_c(size_t, const char *, unsigned int); +void * xcalloc_c(size_t, size_t, const char *, unsigned int); +void * xreallocarray_c(void *, size_t, size_t, const char *, unsigned int); +char * xstrdup_c(const char *, const char *, unsigned int); +void xfree_c(void *, const char *, unsigned int); #endif /* __XALLOC_H__ */