aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code/table.c
diff options
context:
space:
mode:
authorNick Barnes2001-10-31 14:40:56 +0000
committerNick Barnes2001-10-31 14:40:56 +0000
commit7acfca905d76140f4cc0b09c9a12de237de364cd (patch)
tree3ed8babfa3a73d30f29e08ca5d5adcda4ca4e826 /mps/code/table.c
parentb7ce4893f9902d57cd67ac9a92fa6c3d5a8fc833 (diff)
downloademacs-7acfca905d76140f4cc0b09c9a12de237de364cd.tar.gz
emacs-7acfca905d76140f4cc0b09c9a12de237de364cd.zip
Branch imports for masters.
Copied from Perforce Change: 23678 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code/table.c')
-rw-r--r--mps/code/table.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/mps/code/table.c b/mps/code/table.c
new file mode 100644
index 00000000000..edc8fb884b4
--- /dev/null
+++ b/mps/code/table.c
@@ -0,0 +1,279 @@
1/* impl.h.table: A dictionary mapping a Word to a void*
2 *
3 * $HopeName$
4 * Copyright (C) 1999 Harlequin Limited. All rights reserved.
5 *
6 * .note.good-hash: As is common in hash table implementations, we
7 * assume that the hash function is good.
8 */
9
10#include "table.h"
11#include "mpmtypes.h"
12
13#include <stddef.h>
14#include <stdlib.h>
15#include <assert.h>
16#include <stdio.h>
17#include "mpstd.h"
18#ifdef MPS_OS_SU
19#include "ossu.h"
20#endif
21
22
23typedef unsigned long ulong;
24
25
26#define tableUNUSED ((Word)0x2AB7E040)
27#define tableDELETED ((Word)0x2AB7EDE7)
28#define tableACTIVE ((Word)0x2AB7EAC2)
29
30
31typedef struct TableEntryStruct *TableEntry;
32typedef struct TableEntryStruct {
33 Word status;
34 Word key;
35 void *value;
36} TableEntryStruct;
37
38
39typedef struct TableStruct {
40 size_t length;
41 size_t count;
42 size_t limit;
43 TableEntry array;
44} TableStruct;
45
46
47
48/* sizeFloorLog2 -- logarithm base 2 */
49
50static size_t sizeFloorLog2(size_t size)
51{
52 size_t l = 0;
53
54 assert(size != 0);
55 while(size > 1) {
56 ++l;
57 size >>= 1;
58 }
59 return l;
60}
61
62
63/* TableHash -- table hashing function */
64
65static ulong TableHash(Word key)
66{
67 /* Shift some randomness into the low bits. */
68 return (key >> 10) + key;
69}
70
71
72/* TableFind -- finds the entry for this key, or NULL
73 *
74 * .worst: In the worst case, this looks at every slot before giving up,
75 * but that's what you have to do in a closed hash table, to make sure
76 * that all the items still fit in after growing the table.
77 */
78
79static TableEntry TableFind(Table table, Word key, int skip_deleted)
80{
81 ulong hash;
82 size_t i, mask = table->length - 1;
83
84 hash = TableHash(key) & mask;
85 i = hash;
86 do {
87 switch (table->array[i].status) {
88 case tableACTIVE:
89 if (table->array[i].key == key)
90 return &table->array[i];
91 break;
92 case tableDELETED:
93 if (!skip_deleted)
94 return &table->array[i];
95 break;
96 case tableUNUSED:
97 return &table->array[i];
98 break;
99 }
100 i = (i + 1) & mask;
101 } while(i != hash);
102
103 return NULL;
104}
105
106
107/* TableGrow -- doubles the size of the table */
108
109static Res TableGrow(Table table)
110{
111 TableEntry oldArray, newArray;
112 size_t i, oldLength, newLength;
113
114 oldLength = table->length;
115 oldArray = table->array;
116 newLength = oldLength * 2;
117 newArray = malloc(sizeof(TableEntryStruct) * newLength);
118 if(newArray == NULL) return ResMEMORY;
119
120 for(i = 0; i < newLength; ++i) {
121 newArray[i].key = 0;
122 newArray[i].value = NULL;
123 newArray[i].status = tableUNUSED;
124 }
125
126 table->length = newLength;
127 table->array = newArray;
128 table->limit *= 2;
129
130 for(i = 0; i < oldLength; ++i) {
131 if (oldArray[i].status == tableACTIVE) {
132 TableEntry entry;
133 entry = TableFind(table, oldArray[i].key, 0 /* none deleted */);
134 assert(entry != NULL);
135 assert(entry->status == tableUNUSED);
136 entry->key = oldArray[i].key;
137 entry->value = oldArray[i].value;
138 entry->status = tableACTIVE;
139 }
140 }
141 free(oldArray);
142
143 return ResOK;
144}
145
146
147/* TableCreate -- makes a new table */
148
149extern Res TableCreate(Table *tableReturn, size_t length)
150{
151 Table table;
152 size_t i;
153
154 assert(tableReturn != NULL);
155
156 table = malloc(sizeof(TableStruct));
157 if(table == NULL) goto failMallocTable;
158 if (length < 2) length = 2;
159 /* Table size is length rounded up to the next power of 2. */
160 table->length = 1 << (sizeFloorLog2(length-1) + 1);
161 table->count = 0;
162 table->limit = (size_t)(.5 * length);
163 table->array = malloc(sizeof(TableEntryStruct) * length);
164 if(table->array == NULL) goto failMallocArray;
165 for(i = 0; i < length; ++i) {
166 table->array[i].key = 0;
167 table->array[i].value = NULL;
168 table->array[i].status = tableUNUSED;
169 }
170
171 *tableReturn = table;
172 return ResOK;
173
174failMallocArray:
175 free(table);
176failMallocTable:
177 return ResMEMORY;
178}
179
180
181/* TableDestroy -- destroy a table */
182
183extern void TableDestroy(Table table)
184{
185 assert(table != NULL);
186 free(table->array);
187 free(table);
188}
189
190
191/* TableLookup -- look up */
192
193extern Bool TableLookup(void **valueReturn, Table table, Word key)
194{
195 TableEntry entry = TableFind(table, key, 1 /* skip deleted */);
196
197 if(entry == NULL || entry->status != tableACTIVE)
198 return FALSE;
199 *valueReturn = entry->value;
200 return TRUE;
201}
202
203
204/* TableDefine -- add a new mapping */
205
206extern Res TableDefine(Table table, Word key, void *value)
207{
208 TableEntry entry;
209
210 if (table->count >= table->limit) {
211 Res res = TableGrow(table);
212 if(res != ResOK) return res;
213 entry = TableFind(table, key, 0 /* no deletions yet */);
214 assert(entry != NULL);
215 if (entry->status == tableACTIVE)
216 return ResFAIL;
217 } else {
218 entry = TableFind(table, key, 1 /* skip deleted */);
219 if (entry != NULL && entry->status == tableACTIVE)
220 return ResFAIL;
221 /* Search again to find the best slot, deletions included. */
222 entry = TableFind(table, key, 0 /* don't skip deleted */);
223 assert(entry != NULL);
224 }
225
226 entry->status = tableACTIVE;
227 entry->key = key;
228 entry->value = value;
229 ++table->count;
230
231 return ResOK;
232}
233
234
235/* TableRedefine -- redefine an existing mapping */
236
237extern Res TableRedefine(Table table, Word key, void *value)
238{
239 TableEntry entry = TableFind(table, key, 1 /* skip deletions */);
240
241 if (entry == NULL || entry->status != tableACTIVE)
242 return ResFAIL;
243 assert(entry->key == key);
244 entry->value = value;
245 return ResOK;
246}
247
248
249/* TableRemove -- remove a mapping */
250
251extern Res TableRemove(Table table, Word key)
252{
253 TableEntry entry = TableFind(table, key, 1);
254
255 if (entry == NULL || entry->status != tableACTIVE)
256 return ResFAIL;
257 entry->status = tableDELETED;
258 --table->count;
259 return ResOK;
260}
261
262
263/* TableMap -- apply a function to all the mappings */
264
265extern void TableMap(Table table, void(*fun)(Word key, void*value))
266{
267 size_t i;
268 for (i = 0; i < table->length; i++)
269 if (table->array[i].status == tableACTIVE)
270 (*fun)(table->array[i].key, table->array[i].value);
271}
272
273
274/* TableCount -- count the number of mappings in the table */
275
276extern size_t TableCount(Table table)
277{
278 return table->count;
279}