]> git.ipfire.org Git - thirdparty/glibc.git/blame - misc/hsearch_r.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / misc / hsearch_r.c
CommitLineData
6d7e8eda 1/* Copyright (C) 1993-2023 Free Software Foundation, Inc.
2c6fe0bd 2 This file is part of the GNU C Library.
60478656 3
2c6fe0bd 4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
60478656 8
2c6fe0bd
UD
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 12 Lesser General Public License for more details.
60478656 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6 15 License along with the GNU C Library; if not, see
5a82c748 16 <https://www.gnu.org/licenses/>. */
60478656
RM
17
18#include <errno.h>
19#include <malloc.h>
20#include <string.h>
2f5c1750 21#include <stdint.h>
60478656 22#include <search.h>
1d2a8245 23#include <limits.h>
60478656
RM
24
25/* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
26 [Knuth] The Art of Computer Programming, part 3 (6.4) */
27
28
845dcb57 29/* The reentrant version has no static variables to maintain the state.
60478656
RM
30 Instead the interface of all functions is extended to take an argument
31 which describes the current status. */
32typedef struct _ENTRY
bbed653c 33{
d68171ed 34 unsigned int used;
60478656
RM
35 ENTRY entry;
36}
37_ENTRY;
38
39
40/* For the used double hash method the table size has to be a prime. To
41 correct the user given table size we need a prime test. This trivial
42 algorithm is adequate because
43 a) the code is (most probably) called a few times per program run and
44 b) the number is small because the table must fit in the core */
45static int
bbed653c 46isprime (unsigned int number)
60478656
RM
47{
48 /* no even number will be passed */
bae7c7c7
FW
49 for (unsigned int div = 3; div <= number / div; div += 2)
50 if (number % div == 0)
51 return 0;
52 return 1;
60478656
RM
53}
54
60478656
RM
55/* Before using the hash table we must allocate memory for it.
56 Test for an existing table are done. We allocate one element
57 more as the found prime number says. This is done for more effective
58 indexing as explained in the comment for the hsearch function.
bbed653c 59 The contents of the table is zeroed, especially the field used
60478656
RM
60 becomes zero. */
61int
9d46370c 62__hcreate_r (size_t nel, struct hsearch_data *htab)
60478656
RM
63{
64 /* Test for correct arguments. */
65 if (htab == NULL)
66 {
c4029823 67 __set_errno (EINVAL);
60478656
RM
68 return 0;
69 }
70
71 /* There is still another table active. Return with error. */
72 if (htab->table != NULL)
73 return 0;
74
8073a494
UD
75 /* We need a size of at least 3. Otherwise the hash functions we
76 use will not work. */
77 if (nel < 3)
78 nel = 3;
bae7c7c7
FW
79
80 /* Change nel to the first prime number in the range [nel, UINT_MAX - 2],
81 The '- 2' means 'nel += 2' cannot overflow. */
82 for (nel |= 1; ; nel += 2)
83 {
84 if (UINT_MAX - 2 < nel)
85 {
86 __set_errno (ENOMEM);
87 return 0;
88 }
89 if (isprime (nel))
90 break;
91 }
60478656
RM
92
93 htab->size = nel;
94 htab->filled = 0;
95
96 /* allocate memory and zero out */
97 htab->table = (_ENTRY *) calloc (htab->size + 1, sizeof (_ENTRY));
98 if (htab->table == NULL)
99 return 0;
100
101 /* everything went alright */
102 return 1;
103}
4ffb1771
JM
104libc_hidden_def (__hcreate_r)
105weak_alias (__hcreate_r, hcreate_r)
60478656
RM
106
107
108/* After using the hash table it has to be destroyed. The used memory can
109 be freed and the local static variable can be marked as not used. */
110void
9d46370c 111__hdestroy_r (struct hsearch_data *htab)
60478656
RM
112{
113 /* Test for correct arguments. */
114 if (htab == NULL)
115 {
c4029823 116 __set_errno (EINVAL);
60478656
RM
117 return;
118 }
119
ee314200
UD
120 /* Free used memory. */
121 free (htab->table);
60478656 122
bbed653c 123 /* the sign for an existing table is an value != NULL in htable */
60478656
RM
124 htab->table = NULL;
125}
4ffb1771
JM
126libc_hidden_def (__hdestroy_r)
127weak_alias (__hdestroy_r, hdestroy_r)
60478656
RM
128
129
6d52618b 130/* This is the search function. It uses double hashing with open addressing.
60478656
RM
131 The argument item.key has to be a pointer to an zero terminated, most
132 probably strings of chars. The function for generating a number of the
133 strings is simple but fast. It can be replaced by a more complex function
134 like ajw (see [Aho,Sethi,Ullman]) if the needs are shown.
bbed653c 135
60478656
RM
136 We use an trick to speed up the lookup. The table is created by hcreate
137 with one more element available. This enables us to use the index zero
138 special. This index will never be used because we store the first hash
139 index in the field used where zero means not used. Every other value
140 means used. The used field can be used as a first fast comparison for
141 equality of the stored and the parameter value. This helps to prevent
142 unnecessary expensive calls of strcmp. */
143int
f63f2bfd
JM
144__hsearch_r (ENTRY item, ACTION action, ENTRY **retval,
145 struct hsearch_data *htab)
60478656
RM
146{
147 unsigned int hval;
148 unsigned int count;
149 unsigned int len = strlen (item.key);
150 unsigned int idx;
151
60478656
RM
152 /* Compute an value for the given string. Perhaps use a better method. */
153 hval = len;
154 count = len;
155 while (count-- > 0)
156 {
157 hval <<= 4;
158 hval += item.key[count];
159 }
c2d5bd5b
UD
160 if (hval == 0)
161 ++hval;
60478656
RM
162
163 /* First hash function: simply take the modul but prevent zero. */
64647f9a 164 idx = hval % htab->size + 1;
60478656
RM
165
166 if (htab->table[idx].used)
167 {
168 /* Further action might be required according to the action value. */
60478656
RM
169 if (htab->table[idx].used == hval
170 && strcmp (item.key, htab->table[idx].entry.key) == 0)
171 {
60478656
RM
172 *retval = &htab->table[idx].entry;
173 return 1;
174 }
175
176 /* Second hash function, as suggested in [Knuth] */
64647f9a
UD
177 unsigned int hval2 = 1 + hval % (htab->size - 2);
178 unsigned int first_idx = idx;
bbed653c 179
60478656
RM
180 do
181 {
182 /* Because SIZE is prime this guarantees to step through all
14ef9c18 183 available indices. */
60478656
RM
184 if (idx <= hval2)
185 idx = htab->size + idx - hval2;
186 else
187 idx -= hval2;
188
6973fc01 189 /* If we visited all entries leave the loop unsuccessfully. */
64647f9a 190 if (idx == first_idx)
6973fc01
UD
191 break;
192
60478656
RM
193 /* If entry is found use it. */
194 if (htab->table[idx].used == hval
195 && strcmp (item.key, htab->table[idx].entry.key) == 0)
196 {
60478656
RM
197 *retval = &htab->table[idx].entry;
198 return 1;
199 }
200 }
201 while (htab->table[idx].used);
202 }
203
204 /* An empty bucket has been found. */
205 if (action == ENTER)
206 {
2604afb1
UD
207 /* If table is full and another entry should be entered return
208 with error. */
71b8b018 209 if (htab->filled == htab->size)
2604afb1
UD
210 {
211 __set_errno (ENOMEM);
212 *retval = NULL;
213 return 0;
214 }
215
60478656
RM
216 htab->table[idx].used = hval;
217 htab->table[idx].entry = item;
218
219 ++htab->filled;
220
221 *retval = &htab->table[idx].entry;
222 return 1;
223 }
224
c4029823 225 __set_errno (ESRCH);
60478656
RM
226 *retval = NULL;
227 return 0;
228}
4ffb1771
JM
229libc_hidden_def (__hsearch_r)
230weak_alias (__hsearch_r, hsearch_r)