annotate lib/tsearch.c @ 17326:bb52d9cece01

unsetenv etc.: port to Solaris 11 + GNU Emacs * lib/canonicalize-lgpl.c, lib/getaddrinfo.c, lib/getdelim.c: * lib/glob.c, lib/random_r.c, lib/setenv.c, lib/tsearch.c: * lib/unsetenv.c (_GL_ARG_NONNULL): Define before including <config.h>. GNU Emacs's <config.h> includes <stdlib.h> (which is not a great idea but is too painful to fix right now), and without this gnulib change <stdlib.h> was defining _GL_ARG_NONNULL incorrectly when compiling unsetenv.c on Solaris 11. Fix the problem for unsetenv.c, and fix other similar occurrences.
author Paul Eggert <eggert@cs.ucla.edu>
date Mon, 11 Feb 2013 14:58:56 -0800
parents e542fd46ad6f
children 344018b6e5d7
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
17249
e542fd46ad6f maint: update all copyright year number ranges
Eric Blake <eblake@redhat.com>
parents: 16201
diff changeset
1 /* Copyright (C) 1995-1997, 2000, 2006-2007, 2009-2013 Free Software
12559
c2cbabec01dd update nearly all FSF copyright year lists to include 2010
Jim Meyering <meyering@redhat.com>
parents: 12422
diff changeset
2 Foundation, Inc.
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
3 Contributed by Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>, 1997.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
4
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
5 NOTE: The canonical source of this file is maintained with the GNU C
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
6 Library. Bugs can be reported to bug-glibc@gnu.org.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
7
9309
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 8532
diff changeset
8 This program is free software: you can redistribute it and/or modify it
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
9 under the terms of the GNU General Public License as published by the
9309
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 8532
diff changeset
10 Free Software Foundation; either version 3 of the License, or any
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
11 later version.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
12
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
13 This program is distributed in the hope that it will be useful,
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
16 GNU General Public License for more details.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
17
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
18 You should have received a copy of the GNU General Public License
9309
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 8532
diff changeset
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
20
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
21 /* Tree search for red/black trees.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
22 The algorithm for adding nodes is taken from one of the many "Algorithms"
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
23 books by Robert Sedgewick, although the implementation differs.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
24 The algorithm for deleting nodes can probably be found in a book named
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
25 "Introduction to Algorithms" by Cormen/Leiserson/Rivest. At least that's
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
26 the book that my professor took most algorithms from during the "Data
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
27 Structures" course...
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
28
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
29 Totally public domain. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
30
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
31 /* Red/black trees are binary trees in which the edges are colored either red
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
32 or black. They have the following properties:
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
33 1. The number of black edges on every path from the root to a leaf is
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
34 constant.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
35 2. No two red edges are adjacent.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
36 Therefore there is an upper bound on the length of every path, it's
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
37 O(log n) where n is the number of nodes in the tree. No path can be longer
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
38 than 1+2*P where P is the length of the shortest path in the tree.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
39 Useful for the implementation:
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
40 3. If one of the children of a node is NULL, then the other one is red
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
41 (if it exists).
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
42
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
43 In the implementation, not the edges are colored, but the nodes. The color
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
44 interpreted as the color of the edge leading to this node. The color is
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
45 meaningless for the root node, but we color the root node black for
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
46 convenience. All added nodes are red initially.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
47
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
48 Adding to a red/black tree is rather easy. The right place is searched
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
49 with a usual binary tree search. Additionally, whenever a node N is
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
50 reached that has two red successors, the successors are colored black and
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
51 the node itself colored red. This moves red edges up the tree where they
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
52 pose less of a problem once we get to really insert the new node. Changing
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
53 N's color to red may violate rule 2, however, so rotations may become
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
54 necessary to restore the invariants. Adding a new red leaf may violate
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
55 the same rule, so afterwards an additional check is run and the tree
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
56 possibly rotated.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
57
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
58 Deleting is hairy. There are mainly two nodes involved: the node to be
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
59 deleted (n1), and another node that is to be unchained from the tree (n2).
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
60 If n1 has a successor (the node with a smallest key that is larger than
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
61 n1), then the successor becomes n2 and its contents are copied into n1,
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
62 otherwise n1 becomes n2.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
63 Unchaining a node may violate rule 1: if n2 is black, one subtree is
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
64 missing one black edge afterwards. The algorithm must try to move this
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
65 error upwards towards the root, so that the subtree that does not have
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
66 enough black edges becomes the whole tree. Once that happens, the error
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
67 has disappeared. It may not be necessary to go all the way up, since it
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
68 is possible that rotations and recoloring can fix the error before that.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
69
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
70 Although the deletion algorithm must walk upwards through the tree, we
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
71 do not store parent pointers in the nodes. Instead, delete allocates a
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
72 small array of parent pointers and fills it while descending the tree.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
73 Since we know that the length of a path is O(log n), where n is the number
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
74 of nodes, this is likely to use less memory. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
75
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
76 /* Tree rotations look like this:
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
77 A C
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
78 / \ / \
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
79 B C A G
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
80 / \ / \ --> / \
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
81 D E F G B F
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
82 / \
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
83 D E
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
84
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
85 In this case, A has been rotated left. This preserves the ordering of the
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
86 binary tree. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
87
12422
f7842310a565 New module 'arg-nonnull'. Declare which arguments expect non-NULL values.
Bruno Haible <bruno@clisp.org>
parents: 12421
diff changeset
88 /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
f7842310a565 New module 'arg-nonnull'. Declare which arguments expect non-NULL values.
Bruno Haible <bruno@clisp.org>
parents: 12421
diff changeset
89 optimizes away the rootp == NULL tests below. */
f7842310a565 New module 'arg-nonnull'. Declare which arguments expect non-NULL values.
Bruno Haible <bruno@clisp.org>
parents: 12421
diff changeset
90 #define _GL_ARG_NONNULL(params)
f7842310a565 New module 'arg-nonnull'. Declare which arguments expect non-NULL values.
Bruno Haible <bruno@clisp.org>
parents: 12421
diff changeset
91
17326
bb52d9cece01 unsetenv etc.: port to Solaris 11 + GNU Emacs
Paul Eggert <eggert@cs.ucla.edu>
parents: 17249
diff changeset
92 #include <config.h>
bb52d9cece01 unsetenv etc.: port to Solaris 11 + GNU Emacs
Paul Eggert <eggert@cs.ucla.edu>
parents: 17249
diff changeset
93
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
94 /* Specification. */
8532
11f6a87d953a New module 'search'.
Bruno Haible <bruno@clisp.org>
parents: 7585
diff changeset
95 #ifdef IN_LIBINTL
11f6a87d953a New module 'search'.
Bruno Haible <bruno@clisp.org>
parents: 7585
diff changeset
96 # include "tsearch.h"
11f6a87d953a New module 'search'.
Bruno Haible <bruno@clisp.org>
parents: 7585
diff changeset
97 #else
11f6a87d953a New module 'search'.
Bruno Haible <bruno@clisp.org>
parents: 7585
diff changeset
98 # include <search.h>
11f6a87d953a New module 'search'.
Bruno Haible <bruno@clisp.org>
parents: 7585
diff changeset
99 #endif
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
100
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
101 #include <stdlib.h>
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
102
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
103 typedef int (*__compar_fn_t) (const void *, const void *);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
104 typedef void (*__action_fn_t) (const void *, VISIT, int);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
105
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
106 #ifndef weak_alias
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
107 # define __tsearch tsearch
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
108 # define __tfind tfind
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
109 # define __tdelete tdelete
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
110 # define __twalk twalk
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
111 #endif
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
112
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
113 #ifndef internal_function
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
114 /* Inside GNU libc we mark some function in a special way. In other
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
115 environments simply ignore the marking. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
116 # define internal_function
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
117 #endif
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
118
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
119 typedef struct node_t
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
120 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
121 /* Callers expect this to be the first element in the structure - do not
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
122 move! */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
123 const void *key;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
124 struct node_t *left;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
125 struct node_t *right;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
126 unsigned int red:1;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
127 } *node;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
128 typedef const struct node_t *const_node;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
129
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
130 #undef DEBUGGING
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
131
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
132 #ifdef DEBUGGING
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
133
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
134 /* Routines to check tree invariants. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
135
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
136 #include <assert.h>
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
137
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
138 #define CHECK_TREE(a) check_tree(a)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
139
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
140 static void
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
141 check_tree_recurse (node p, int d_sofar, int d_total)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
142 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
143 if (p == NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
144 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
145 assert (d_sofar == d_total);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
146 return;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
147 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
148
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
149 check_tree_recurse (p->left, d_sofar + (p->left && !p->left->red), d_total);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
150 check_tree_recurse (p->right, d_sofar + (p->right && !p->right->red), d_total);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
151 if (p->left)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
152 assert (!(p->left->red && p->red));
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
153 if (p->right)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
154 assert (!(p->right->red && p->red));
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
155 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
156
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
157 static void
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
158 check_tree (node root)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
159 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
160 int cnt = 0;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
161 node p;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
162 if (root == NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
163 return;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
164 root->red = 0;
13051
094f6cfdb5c3 Minor formatting changes.
Bruno Haible <bruno@clisp.org>
parents: 12559
diff changeset
165 for (p = root->left; p; p = p->left)
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
166 cnt += !p->red;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
167 check_tree_recurse (root, 0, cnt);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
168 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
169
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
170
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
171 #else
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
172
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
173 #define CHECK_TREE(a)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
174
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
175 #endif
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
176
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
177 /* Possibly "split" a node with two red successors, and/or fix up two red
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
178 edges in a row. ROOTP is a pointer to the lowest node we visited, PARENTP
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
179 and GPARENTP pointers to its parent/grandparent. P_R and GP_R contain the
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
180 comparison values that determined which way was taken in the tree to reach
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
181 ROOTP. MODE is 1 if we need not do the split, but must check for two red
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
182 edges between GPARENTP and ROOTP. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
183 static void
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
184 maybe_split_for_insert (node *rootp, node *parentp, node *gparentp,
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
185 int p_r, int gp_r, int mode)
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
186 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
187 node root = *rootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
188 node *rp, *lp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
189 rp = &(*rootp)->right;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
190 lp = &(*rootp)->left;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
191
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
192 /* See if we have to split this node (both successors red). */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
193 if (mode == 1
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
194 || ((*rp) != NULL && (*lp) != NULL && (*rp)->red && (*lp)->red))
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
195 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
196 /* This node becomes red, its successors black. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
197 root->red = 1;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
198 if (*rp)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
199 (*rp)->red = 0;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
200 if (*lp)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
201 (*lp)->red = 0;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
202
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
203 /* If the parent of this node is also red, we have to do
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
204 rotations. */
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
205 if (parentp != NULL && (*parentp)->red)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
206 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
207 node gp = *gparentp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
208 node p = *parentp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
209 /* There are two main cases:
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
210 1. The edge types (left or right) of the two red edges differ.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
211 2. Both red edges are of the same type.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
212 There exist two symmetries of each case, so there is a total of
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
213 4 cases. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
214 if ((p_r > 0) != (gp_r > 0))
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
215 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
216 /* Put the child at the top of the tree, with its parent
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
217 and grandparent as successors. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
218 p->red = 1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
219 gp->red = 1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
220 root->red = 0;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
221 if (p_r < 0)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
222 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
223 /* Child is left of parent. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
224 p->left = *rp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
225 *rp = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
226 gp->right = *lp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
227 *lp = gp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
228 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
229 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
230 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
231 /* Child is right of parent. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
232 p->right = *lp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
233 *lp = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
234 gp->left = *rp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
235 *rp = gp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
236 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
237 *gparentp = root;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
238 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
239 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
240 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
241 *gparentp = *parentp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
242 /* Parent becomes the top of the tree, grandparent and
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
243 child are its successors. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
244 p->red = 0;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
245 gp->red = 1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
246 if (p_r < 0)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
247 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
248 /* Left edges. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
249 gp->left = p->right;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
250 p->right = gp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
251 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
252 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
253 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
254 /* Right edges. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
255 gp->right = p->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
256 p->left = gp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
257 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
258 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
259 }
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
260 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
261 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
262
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
263 /* Find or insert datum into search tree.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
264 KEY is the key to be located, ROOTP is the address of tree root,
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
265 COMPAR the ordering function. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
266 void *
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
267 __tsearch (const void *key, void **vrootp, __compar_fn_t compar)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
268 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
269 node q;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
270 node *parentp = NULL, *gparentp = NULL;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
271 node *rootp = (node *) vrootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
272 node *nextp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
273 int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
274
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
275 if (rootp == NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
276 return NULL;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
277
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
278 /* This saves some additional tests below. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
279 if (*rootp != NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
280 (*rootp)->red = 0;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
281
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
282 CHECK_TREE (*rootp);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
283
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
284 nextp = rootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
285 while (*nextp != NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
286 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
287 node root = *rootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
288 r = (*compar) (key, root->key);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
289 if (r == 0)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
290 return root;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
291
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
292 maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
293 /* If that did any rotations, parentp and gparentp are now garbage.
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
294 That doesn't matter, because the values they contain are never
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
295 used again in that case. */
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
296
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
297 nextp = r < 0 ? &root->left : &root->right;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
298 if (*nextp == NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
299 break;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
300
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
301 gparentp = parentp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
302 parentp = rootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
303 rootp = nextp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
304
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
305 gp_r = p_r;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
306 p_r = r;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
307 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
308
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
309 q = (struct node_t *) malloc (sizeof (struct node_t));
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
310 if (q != NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
311 {
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
312 *nextp = q; /* link new node to old */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
313 q->key = key; /* initialize new node */
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
314 q->red = 1;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
315 q->left = q->right = NULL;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
316
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
317 if (nextp != rootp)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
318 /* There may be two red edges in a row now, which we must avoid by
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
319 rotating the tree. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
320 maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1);
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
321 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
322
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
323 return q;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
324 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
325 #ifdef weak_alias
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
326 weak_alias (__tsearch, tsearch)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
327 #endif
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
328
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
329
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
330 /* Find datum in search tree.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
331 KEY is the key to be located, ROOTP is the address of tree root,
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
332 COMPAR the ordering function. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
333 void *
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
334 __tfind (key, vrootp, compar)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
335 const void *key;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
336 void *const *vrootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
337 __compar_fn_t compar;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
338 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
339 node *rootp = (node *) vrootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
340
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
341 if (rootp == NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
342 return NULL;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
343
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
344 CHECK_TREE (*rootp);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
345
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
346 while (*rootp != NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
347 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
348 node root = *rootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
349 int r;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
350
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
351 r = (*compar) (key, root->key);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
352 if (r == 0)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
353 return root;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
354
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
355 rootp = r < 0 ? &root->left : &root->right;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
356 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
357 return NULL;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
358 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
359 #ifdef weak_alias
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
360 weak_alias (__tfind, tfind)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
361 #endif
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
362
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
363
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
364 /* Delete node with given key.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
365 KEY is the key to be deleted, ROOTP is the address of the root of tree,
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
366 COMPAR the comparison function. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
367 void *
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
368 __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
369 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
370 node p, q, r, retval;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
371 int cmp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
372 node *rootp = (node *) vrootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
373 node root, unchained;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
374 /* Stack of nodes so we remember the parents without recursion. It's
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
375 _very_ unlikely that there are paths longer than 40 nodes. The tree
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
376 would need to have around 250.000 nodes. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
377 int stacksize = 100;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
378 int sp = 0;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
379 node *nodestack[100];
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
380
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
381 if (rootp == NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
382 return NULL;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
383 p = *rootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
384 if (p == NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
385 return NULL;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
386
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
387 CHECK_TREE (p);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
388
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
389 while ((cmp = (*compar) (key, (*rootp)->key)) != 0)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
390 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
391 if (sp == stacksize)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
392 abort ();
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
393
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
394 nodestack[sp++] = rootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
395 p = *rootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
396 rootp = ((cmp < 0)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
397 ? &(*rootp)->left
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
398 : &(*rootp)->right);
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
399 if (*rootp == NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
400 return NULL;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
401 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
402
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
403 /* This is bogus if the node to be deleted is the root... this routine
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
404 really should return an integer with 0 for success, -1 for failure
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
405 and errno = ESRCH or something. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
406 retval = p;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
407
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
408 /* We don't unchain the node we want to delete. Instead, we overwrite
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
409 it with its successor and unchain the successor. If there is no
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
410 successor, we really unchain the node to be deleted. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
411
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
412 root = *rootp;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
413
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
414 r = root->right;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
415 q = root->left;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
416
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
417 if (q == NULL || r == NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
418 unchained = root;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
419 else
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
420 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
421 node *parent = rootp, *up = &root->right;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
422 for (;;)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
423 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
424 if (sp == stacksize)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
425 abort ();
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
426 nodestack[sp++] = parent;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
427 parent = up;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
428 if ((*up)->left == NULL)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
429 break;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
430 up = &(*up)->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
431 }
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
432 unchained = *up;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
433 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
434
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
435 /* We know that either the left or right successor of UNCHAINED is NULL.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
436 R becomes the other one, it is chained into the parent of UNCHAINED. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
437 r = unchained->left;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
438 if (r == NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
439 r = unchained->right;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
440 if (sp == 0)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
441 *rootp = r;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
442 else
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
443 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
444 q = *nodestack[sp-1];
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
445 if (unchained == q->right)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
446 q->right = r;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
447 else
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
448 q->left = r;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
449 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
450
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
451 if (unchained != root)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
452 root->key = unchained->key;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
453 if (!unchained->red)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
454 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
455 /* Now we lost a black edge, which means that the number of black
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
456 edges on every path is no longer constant. We must balance the
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
457 tree. */
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
458 /* NODESTACK now contains all parents of R. R is likely to be NULL
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
459 in the first iteration. */
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
460 /* NULL nodes are considered black throughout - this is necessary for
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
461 correctness. */
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
462 while (sp > 0 && (r == NULL || !r->red))
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
463 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
464 node *pp = nodestack[sp - 1];
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
465 p = *pp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
466 /* Two symmetric cases. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
467 if (r == p->left)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
468 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
469 /* Q is R's brother, P is R's parent. The subtree with root
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
470 R has one black edge less than the subtree with root Q. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
471 q = p->right;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
472 if (q->red)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
473 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
474 /* If Q is red, we know that P is black. We rotate P left
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
475 so that Q becomes the top node in the tree, with P below
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
476 it. P is colored red, Q is colored black.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
477 This action does not change the black edge count for any
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
478 leaf in the tree, but we will be able to recognize one
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
479 of the following situations, which all require that Q
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
480 is black. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
481 q->red = 0;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
482 p->red = 1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
483 /* Left rotate p. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
484 p->right = q->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
485 q->left = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
486 *pp = q;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
487 /* Make sure pp is right if the case below tries to use
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
488 it. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
489 nodestack[sp++] = pp = &q->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
490 q = p->right;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
491 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
492 /* We know that Q can't be NULL here. We also know that Q is
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
493 black. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
494 if ((q->left == NULL || !q->left->red)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
495 && (q->right == NULL || !q->right->red))
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
496 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
497 /* Q has two black successors. We can simply color Q red.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
498 The whole subtree with root P is now missing one black
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
499 edge. Note that this action can temporarily make the
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
500 tree invalid (if P is red). But we will exit the loop
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
501 in that case and set P black, which both makes the tree
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
502 valid and also makes the black edge count come out
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
503 right. If P is black, we are at least one step closer
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
504 to the root and we'll try again the next iteration. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
505 q->red = 1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
506 r = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
507 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
508 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
509 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
510 /* Q is black, one of Q's successors is red. We can
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
511 repair the tree with one operation and will exit the
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
512 loop afterwards. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
513 if (q->right == NULL || !q->right->red)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
514 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
515 /* The left one is red. We perform the same action as
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
516 in maybe_split_for_insert where two red edges are
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
517 adjacent but point in different directions:
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
518 Q's left successor (let's call it Q2) becomes the
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
519 top of the subtree we are looking at, its parent (Q)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
520 and grandparent (P) become its successors. The former
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
521 successors of Q2 are placed below P and Q.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
522 P becomes black, and Q2 gets the color that P had.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
523 This changes the black edge count only for node R and
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
524 its successors. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
525 node q2 = q->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
526 q2->red = p->red;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
527 p->right = q2->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
528 q->left = q2->right;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
529 q2->right = q;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
530 q2->left = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
531 *pp = q2;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
532 p->red = 0;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
533 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
534 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
535 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
536 /* It's the right one. Rotate P left. P becomes black,
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
537 and Q gets the color that P had. Q's right successor
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
538 also becomes black. This changes the black edge
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
539 count only for node R and its successors. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
540 q->red = p->red;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
541 p->red = 0;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
542
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
543 q->right->red = 0;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
544
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
545 /* left rotate p */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
546 p->right = q->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
547 q->left = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
548 *pp = q;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
549 }
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
550
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
551 /* We're done. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
552 sp = 1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
553 r = NULL;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
554 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
555 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
556 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
557 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
558 /* Comments: see above. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
559 q = p->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
560 if (q->red)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
561 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
562 q->red = 0;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
563 p->red = 1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
564 p->left = q->right;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
565 q->right = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
566 *pp = q;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
567 nodestack[sp++] = pp = &q->right;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
568 q = p->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
569 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
570 if ((q->right == NULL || !q->right->red)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
571 && (q->left == NULL || !q->left->red))
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
572 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
573 q->red = 1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
574 r = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
575 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
576 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
577 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
578 if (q->left == NULL || !q->left->red)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
579 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
580 node q2 = q->right;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
581 q2->red = p->red;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
582 p->left = q2->right;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
583 q->right = q2->left;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
584 q2->left = q;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
585 q2->right = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
586 *pp = q2;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
587 p->red = 0;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
588 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
589 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
590 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
591 q->red = p->red;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
592 p->red = 0;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
593 q->left->red = 0;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
594 p->left = q->right;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
595 q->right = p;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
596 *pp = q;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
597 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
598 sp = 1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
599 r = NULL;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
600 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
601 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
602 --sp;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
603 }
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
604 if (r != NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
605 r->red = 0;
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
606 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
607
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
608 free (unchained);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
609 return retval;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
610 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
611 #ifdef weak_alias
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
612 weak_alias (__tdelete, tdelete)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
613 #endif
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
614
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
615
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
616 /* Walk the nodes of a tree.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
617 ROOT is the root of the tree to be walked, ACTION the function to be
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
618 called at each node. LEVEL is the level of ROOT in the whole tree. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
619 static void
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
620 internal_function
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
621 trecurse (const void *vroot, __action_fn_t action, int level)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
622 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
623 const_node root = (const_node) vroot;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
624
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
625 if (root->left == NULL && root->right == NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
626 (*action) (root, leaf, level);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
627 else
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
628 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
629 (*action) (root, preorder, level);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
630 if (root->left != NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
631 trecurse (root->left, action, level + 1);
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
632 (*action) (root, postorder, level);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
633 if (root->right != NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
634 trecurse (root->right, action, level + 1);
7585
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
635 (*action) (root, endorder, level);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
636 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
637 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
638
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
639
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
640 /* Walk the nodes of a tree.
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
641 ROOT is the root of the tree to be walked, ACTION the function to be
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
642 called at each node. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
643 void
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
644 __twalk (const void *vroot, __action_fn_t action)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
645 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
646 const_node root = (const_node) vroot;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
647
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
648 CHECK_TREE (root);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
649
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
650 if (root != NULL && action != NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
651 trecurse (root, action, 0);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
652 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
653 #ifdef weak_alias
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
654 weak_alias (__twalk, twalk)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
655 #endif
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
656
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
657
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
658 #ifdef _LIBC
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
659
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
660 /* The standardized functions miss an important functionality: the
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
661 tree cannot be removed easily. We provide a function to do this. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
662 static void
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
663 internal_function
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
664 tdestroy_recurse (node root, __free_fn_t freefct)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
665 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
666 if (root->left != NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
667 tdestroy_recurse (root->left, freefct);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
668 if (root->right != NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
669 tdestroy_recurse (root->right, freefct);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
670 (*freefct) ((void *) root->key);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
671 /* Free the node itself. */
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
672 free (root);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
673 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
674
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
675 void
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
676 __tdestroy (void *vroot, __free_fn_t freefct)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
677 {
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
678 node root = (node) vroot;
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
679
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
680 CHECK_TREE (root);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
681
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
682 if (root != NULL)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
683 tdestroy_recurse (root, freefct);
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
684 }
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
685 weak_alias (__tdestroy, tdestroy)
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
686
0cac6db530a1 New module 'tsearch'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
687 #endif /* _LIBC */