chiark / gitweb /
Makefile: Ship versioncmp.in.
[mLib] / hash.c
1 /* -*-c-*-
2  *
3  * $Id: hash.c,v 1.4 2004/04/08 01:36:11 mdw Exp $
4  *
5  * General hashtable infrastructure
6  *
7  * (c) 1999 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------*
11  *
12  * This file is part of the mLib utilities library.
13  *
14  * mLib is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  *
19  * mLib is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU Library General Public
25  * License along with mLib; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Header files ------------------------------------------------------*/
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "alloc.h"
37 #include "arena.h"
38 #include "bits.h"
39 #include "exc.h"
40 #include "hash.h"
41
42 /*----- Main code ---------------------------------------------------------*/
43
44 /* --- @hash_create@ --- *
45  *
46  * Arguments:   @hash_table *t@ = pointer to hashtable to initialize
47  *              @size_t n@ = number of bins to allocate (zero initially)
48  *
49  * Returns:     ---
50  *
51  * Use:         Initializes a hashtable with a given number of bins.  The
52  *              bins are initially empty.  The number of bins must be a power
53  *              of two.  This is not checked.
54  */
55
56 void hash_create(hash_table *t, size_t n)
57 {
58   hash_base **v;
59
60   t->a = arena_global;
61   t->v = x_alloc(t->a, n * sizeof(hash_base *));
62   t->mask = n - 1;
63   for (v = t->v; n; v++, n--)
64     *v = 0;
65 }
66
67 /* --- @hash_destroy@ --- *
68  *
69  * Arguments:   @hash_table *t@ = pointer to hashtable to destroy
70  *
71  * Returns:     ---
72  *
73  * Use:         Frees a hashtable.  The items are not freed: they are the
74  *              responsibility of the implementation.
75  */
76
77 void hash_destroy(hash_table *t) { x_free(t->a, t->v); }
78
79 /* --- @hash_bin@ --- *
80  *
81  * Arguments:   @hash_table *t@ = pointer to hashtable
82  *              @uint32 hash@ = hash value to look up
83  *
84  * Returns:     Pointer to the bin's list head.
85  *
86  * Use:         Given a hash value return the address of the appropriate list
87  *              head.  It is safe to remove the current entry from the table.
88  */
89
90 hash_base **hash_bin(hash_table *t, uint32 hash)
91   { return (HASH_BIN(t, hash)); }
92
93 /* --- @hash_extend@ --- *
94  *
95  * Arguments:   @hash_table *t@ = pointer to hashtable to extend
96  *
97  * Returns:     Nonzero if extension was successful.
98  *
99  * Use:         Extends a hashtable.  The number of bins is doubled and the
100  *              entries are redistributed.
101  */
102
103 int hash_extend(hash_table *t)
104 {
105   hash_base **v;
106   uint32 m = t->mask + 1;
107   size_t i;
108
109   /* --- Allocate a new hash bin vector --- */
110
111   if ((v = A_REALLOC(t->a, t->v,
112                      2 * m * sizeof(hash_base *),
113                      m * sizeof(hash_base *))) == 0) {
114     return (0);
115   }
116   t->v = v;
117   t->mask = (m * 2) - 1;
118
119   /* --- Wander through the table rehashing things --- */
120
121   for (i = 0; i < m; i++) {
122     hash_base **p = v + i;
123     hash_base **q = p + m;
124
125     while (*p) {
126       if (!((*p)->hash & m))
127         p = &(*p)->next;
128       else {
129         *q = *p;
130         q = &(*q)->next;
131         *p = (*p)->next;
132       }
133     }
134     *p = 0;
135     *q = 0;
136   }
137
138   return (1);
139 }
140
141 /* --- @hash_remove@ --- *
142  *
143  * Arguments:   @hash_table *t@ = pointer to hashtable
144  *              @hash_base *p@ = pointer to item to remove
145  *
146  * Returns:     ---
147  *
148  * Use:         Removes an item from a hashtable.  The item itself is not
149  *              freed, although it is removed from the data structure and is
150  *              safe to free.
151  */
152
153 void hash_remove(hash_table *t, hash_base *p)
154 {
155   hash_base **b = HASH_BIN(t, p->hash);
156   while (*b) {
157     if (*b == p) {
158       *b = p->next;
159       return;
160     }
161     b = &(*b)->next;
162   }
163   return;
164 }
165
166 /* --- @hash_mkiter@ --- *
167  *
168  * Arguments:   @hash_iter *i@ = pointer to iterator to create
169  *              @hash_table *t@ = pointer to hashtable to iterate
170  *
171  * Returns:     ---
172  *
173  * Use:         Initializes a hashtable iterator.
174  */
175
176 void hash_mkiter(hash_iter *i, hash_table *t) { HASH_MKITER(i, t); }
177
178 /* --- @hash_next@ --- *
179  *
180  * Arguments:   @hash_iter *i@ = pointer to iterator
181  *
182  * Returns:     Pointer to the next hashtable entry found, or null.
183  *
184  * Use:         Returns the next entry from the hashtable.
185  */
186
187 hash_base *hash_next(hash_iter *i)
188 {
189   hash_base *b;
190   HASH_NEXT(i, b);
191   return (b);
192 }
193
194 /*----- That's all, folks -------------------------------------------------*/