]>
git.ipfire.org Git - thirdparty/bash.git/blob - hashlib.c
1 /* hashlib.c -- functions to manage and access hash tables for bash. */
3 /* Copyright (C) 1987,1989,1991,1995,1998,2001,2003,2005,2006,2008,2009 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
25 #if defined (HAVE_UNISTD_H)
27 # include <sys/types.h>
37 /* Rely on properties of unsigned division (unsigned/int -> unsigned) and
38 don't discard the upper 32 bits of the value, if present. */
39 #define HASH_BUCKET(s, t, h) (((h) = hash_string (s)) & ((t)->nbuckets - 1))
41 static BUCKET_CONTENTS
*copy_bucket_array
__P((BUCKET_CONTENTS
*, sh_string_func_t
*));
43 /* Make a new hash table with BUCKETS number of buckets. Initialize
44 each slot in the table to NULL. */
49 HASH_TABLE
*new_table
;
52 new_table
= (HASH_TABLE
*)xmalloc (sizeof (HASH_TABLE
));
54 buckets
= DEFAULT_HASH_BUCKETS
;
56 new_table
->bucket_array
=
57 (BUCKET_CONTENTS
**)xmalloc (buckets
* sizeof (BUCKET_CONTENTS
*));
58 new_table
->nbuckets
= buckets
;
59 new_table
->nentries
= 0;
61 for (i
= 0; i
< buckets
; i
++)
62 new_table
->bucket_array
[i
] = (BUCKET_CONTENTS
*)NULL
;
71 return (HASH_ENTRIES(table
));
74 static BUCKET_CONTENTS
*
75 copy_bucket_array (ba
, cpdata
)
77 sh_string_func_t
*cpdata
; /* data copy function */
79 BUCKET_CONTENTS
*new_bucket
, *n
, *e
;
82 return ((BUCKET_CONTENTS
*)0);
84 for (n
= (BUCKET_CONTENTS
*)0, e
= ba
; e
; e
= e
->next
)
88 new_bucket
= (BUCKET_CONTENTS
*)xmalloc (sizeof (BUCKET_CONTENTS
));
93 n
->next
= (BUCKET_CONTENTS
*)xmalloc (sizeof (BUCKET_CONTENTS
));
97 n
->key
= savestring (e
->key
);
98 n
->data
= e
->data
? (cpdata
? (*cpdata
) (e
->data
) : savestring (e
->data
))
101 n
->times_found
= e
->times_found
;
102 n
->next
= (BUCKET_CONTENTS
*)NULL
;
109 hash_copy (table
, cpdata
)
111 sh_string_func_t
*cpdata
;
113 HASH_TABLE
*new_table
;
117 return ((HASH_TABLE
*)NULL
);
119 new_table
= hash_create (table
->nbuckets
);
121 for (i
= 0; i
< table
->nbuckets
; i
++)
122 new_table
->bucket_array
[i
] = copy_bucket_array (table
->bucket_array
[i
], cpdata
);
124 new_table
->nentries
= table
->nentries
;
128 /* The `khash' check below requires that strings that compare equally with
129 strcmp hash to the same value. */
134 register unsigned int i
;
136 /* This is the best string hash function I found.
138 The magic is in the interesting relationship between the special prime
139 16777619 (2^24 + 403) and 2^32 and 2^8. */
150 /* Return the location of the bucket which should contain the data
151 for STRING. TABLE is a pointer to a HASH_TABLE. */
154 hash_bucket (string
, table
)
160 return (HASH_BUCKET (string
, table
, h
));
163 /* Return a pointer to the hashed item. If the HASH_CREATE flag is passed,
164 create a new hash table entry for STRING, otherwise return NULL. */
166 hash_search (string
, table
, flags
)
171 BUCKET_CONTENTS
*list
;
175 if (table
== 0 || ((flags
& HASH_CREATE
) == 0 && HASH_ENTRIES (table
) == 0))
176 return (BUCKET_CONTENTS
*)NULL
;
178 bucket
= HASH_BUCKET (string
, table
, hv
);
180 for (list
= table
->bucket_array
? table
->bucket_array
[bucket
] : 0; list
; list
= list
->next
)
182 /* This is the comparison function */
183 if (hv
== list
->khash
&& STREQ (list
->key
, string
))
190 if (flags
& HASH_CREATE
)
192 list
= (BUCKET_CONTENTS
*)xmalloc (sizeof (BUCKET_CONTENTS
));
193 list
->next
= table
->bucket_array
[bucket
];
194 table
->bucket_array
[bucket
] = list
;
197 list
->key
= (char *)string
; /* XXX fix later */
199 list
->times_found
= 0;
205 return (BUCKET_CONTENTS
*)NULL
;
208 /* Remove the item specified by STRING from the hash table TABLE.
209 The item removed is returned, so you can free its contents. If
210 the item isn't in this table NULL is returned. */
212 hash_remove (string
, table
, flags
)
218 BUCKET_CONTENTS
*prev
, *temp
;
221 if (table
== 0 || HASH_ENTRIES (table
) == 0)
222 return (BUCKET_CONTENTS
*)NULL
;
224 bucket
= HASH_BUCKET (string
, table
, hv
);
225 prev
= (BUCKET_CONTENTS
*)NULL
;
226 for (temp
= table
->bucket_array
[bucket
]; temp
; temp
= temp
->next
)
228 if (hv
== temp
->khash
&& STREQ (temp
->key
, string
))
231 prev
->next
= temp
->next
;
233 table
->bucket_array
[bucket
] = temp
->next
;
240 return ((BUCKET_CONTENTS
*) NULL
);
243 /* Create an entry for STRING, in TABLE. If the entry already
244 exists, then return it (unless the HASH_NOSRCH flag is set). */
246 hash_insert (string
, table
, flags
)
251 BUCKET_CONTENTS
*item
;
256 table
= hash_create (0);
258 item
= (flags
& HASH_NOSRCH
) ? (BUCKET_CONTENTS
*)NULL
259 : hash_search (string
, table
, 0);
263 bucket
= HASH_BUCKET (string
, table
, hv
);
265 item
= (BUCKET_CONTENTS
*)xmalloc (sizeof (BUCKET_CONTENTS
));
266 item
->next
= table
->bucket_array
[bucket
];
267 table
->bucket_array
[bucket
] = item
;
272 item
->times_found
= 0;
280 /* Remove and discard all entries in TABLE. If FREE_DATA is non-null, it
281 is a function to call to dispose of a hash item's data. Otherwise,
284 hash_flush (table
, free_data
)
286 sh_free_func_t
*free_data
;
289 register BUCKET_CONTENTS
*bucket
, *item
;
291 if (table
== 0 || HASH_ENTRIES (table
) == 0)
294 for (i
= 0; i
< table
->nbuckets
; i
++)
296 bucket
= table
->bucket_array
[i
];
301 bucket
= bucket
->next
;
304 (*free_data
) (item
->data
);
310 table
->bucket_array
[i
] = (BUCKET_CONTENTS
*)NULL
;
316 /* Free the hash table pointed to by TABLE. */
321 free (table
->bucket_array
);
326 hash_walk (table
, func
)
331 BUCKET_CONTENTS
*item
;
333 if (table
== 0 || HASH_ENTRIES (table
) == 0)
336 for (i
= 0; i
< table
->nbuckets
; i
++)
338 for (item
= hash_items (i
, table
); item
; item
= item
->next
)
339 if ((*func
) (item
) < 0)
344 #if defined (DEBUG) || defined (TEST_HASHING)
346 hash_pstats (table
, name
)
350 register int slot
, bcount
;
351 register BUCKET_CONTENTS
*bc
;
354 name
= "unknown hash table";
356 fprintf (stderr
, "%s: %d buckets; %d items\n", name
, table
->nbuckets
, table
->nentries
);
358 /* Print out a count of how many strings hashed to each bucket, so we can
359 see how even the distribution is. */
360 for (slot
= 0; slot
< table
->nbuckets
; slot
++)
362 bc
= hash_items (slot
, table
);
364 fprintf (stderr
, "\tslot %3d: ", slot
);
365 for (bcount
= 0; bc
; bc
= bc
->next
)
368 fprintf (stderr
, "%d\n", bcount
);
375 /* link with xmalloc.o and lib/malloc/libmalloc.a */
383 HASH_TABLE
*table
, *ntable
;
385 int interrupt_immediately
= 0;
388 signal_is_trapped (s
)
395 programming_error (const char *format
, ...)
401 fatal_error (const char *format
, ...)
407 internal_warning (const char *format
, ...)
417 #if defined (TEST_NBUCKETS)
418 table
= hash_create (TEST_NBUCKETS
);
420 table
= hash_create (0);
426 if (fgets (string
, sizeof (string
), stdin
) == 0)
430 temp_string
= savestring (string
);
431 tt
= hash_insert (temp_string
, table
, 0);
434 fprintf (stderr
, "You have already added item `%s'\n", string
);
443 hash_pstats (table
, "hash test");
445 ntable
= hash_copy (table
, (sh_string_func_t
*)NULL
);
446 hash_flush (table
, (sh_free_func_t
*)NULL
);
447 hash_pstats (ntable
, "hash copy test");
452 #endif /* TEST_HASHING */