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