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