aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code/table.c
diff options
context:
space:
mode:
authorRichard Brooksby2012-09-12 23:00:33 +0100
committerRichard Brooksby2012-09-12 23:00:33 +0100
commite3de034033b4614fa20dde898749d0865d442ef0 (patch)
tree8de85cfceb0577e5459fbc4e88b976d25799ed67 /mps/code/table.c
parent50c50c895b9c98ca0a21fe5edc86ed83d5c5ada8 (diff)
downloademacs-e3de034033b4614fa20dde898749d0865d442ef0.tar.gz
emacs-e3de034033b4614fa20dde898749d0865d442ef0.zip
Responding to nb's review comments.
Copied from Perforce Change: 179457 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code/table.c')
-rw-r--r--mps/code/table.c54
1 files changed, 34 insertions, 20 deletions
diff --git a/mps/code/table.c b/mps/code/table.c
index 7e6b1ec7149..3e5cc0c14ae 100644
--- a/mps/code/table.c
+++ b/mps/code/table.c
@@ -16,7 +16,7 @@
16SRCID(table, "$Id$"); 16SRCID(table, "$Id$");
17 17
18 18
19/* TableHash -- return a hash value from an address 19/* tableHash -- return a hash value from an address
20 * 20 *
21 * This uses a single cycle of an MLCG, more commonly seen as a 21 * This uses a single cycle of an MLCG, more commonly seen as a
22 * pseudorandom number generator. It works extremely well as a 22 * pseudorandom number generator. It works extremely well as a
@@ -36,10 +36,16 @@ SRCID(table, "$Id$");
36 * Of course it's only a 31-bit cycle, so we start by losing the top 36 * Of course it's only a 31-bit cycle, so we start by losing the top
37 * bit of the address, but that's hardly a great problem. 37 * bit of the address, but that's hardly a great problem.
38 * 38 *
39 * See `rnd` in testlib.c for more technical details.
40 *
39 * The implementation is quite subtle. See rnd() in testlib.c, where 41 * The implementation is quite subtle. See rnd() in testlib.c, where
40 * it has been exhaustively (ie: totally) tested. RHSK 2010-12-28. 42 * it has been exhaustively (ie: totally) tested. RHSK 2010-12-28.
41 * 43 *
42 * TODO: Check how this works out on 64-bit. RB 2012-09-04 44 * NOTE: According to NB, still a fine function for producing a 31-bit hash
45 * value, although of course it only hashes on the lower 31 bits of the
46 * key; we could cheaply make it choose a different 31 bits if we'd prefer
47 * (e.g. ((key >> 2) & 0x7FFFFFFF)), or combine more of the key bits (e.g.
48 * ((key ^ (key >> 31)) & 0x7fffffff)).
43 */ 49 */
44 50
45#define R_m 2147483647UL 51#define R_m 2147483647UL
@@ -47,16 +53,16 @@ SRCID(table, "$Id$");
47 53
48typedef Word Hash; 54typedef Word Hash;
49 55
50static Hash TableHash(Word key) 56static Hash tableHash(Word key)
51{ 57{
52 Hash seed = (Hash)(key & 0x7FFFFFFF); 58 Hash hash = (Hash)(key & 0x7FFFFFFF);
53 /* requires m == 2^31-1, a < 2^16 */ 59 /* requires m == 2^31-1, a < 2^16 */
54 Hash bot = R_a * (seed & 0x7FFF); 60 Hash bot = R_a * (hash & 0x7FFF);
55 Hash top = R_a * (seed >> 15); 61 Hash top = R_a * (hash >> 15);
56 seed = bot + ((top & 0xFFFF) << 15) + (top >> 16); 62 hash = bot + ((top & 0xFFFF) << 15) + (top >> 16);
57 if(seed > R_m) 63 if(hash > R_m)
58 seed -= R_m; 64 hash -= R_m;
59 return seed; 65 return hash;
60} 66}
61 67
62 68
@@ -80,14 +86,14 @@ static Bool entryIsActive(Table table, TableEntry entry)
80} 86}
81 87
82 88
83/* TableFind -- finds the entry for this key, or NULL 89/* tableFind -- finds the entry for this key, or NULL
84 * 90 *
85 * .worst: In the worst case, this looks at every slot before giving up, 91 * .worst: In the worst case, this looks at every slot before giving up,
86 * but that's what you have to do in a closed hash table, to make sure 92 * but that's what you have to do in a closed hash table, to make sure
87 * that all the items still fit in after growing the table. 93 * that all the items still fit in after growing the table.
88 */ 94 */
89 95
90static TableEntry TableFind(Table table, Word key, Bool skip_deleted) 96static TableEntry tableFind(Table table, Word key, Bool skip_deleted)
91{ 97{
92 Hash hash; 98 Hash hash;
93 Index i; 99 Index i;
@@ -98,7 +104,7 @@ static TableEntry TableFind(Table table, Word key, Bool skip_deleted)
98 AVER(WordIsP2(table->length)); /* .find.visit */ 104 AVER(WordIsP2(table->length)); /* .find.visit */
99 105
100 mask = table->length - 1; 106 mask = table->length - 1;
101 hash = TableHash(key) & mask; 107 hash = tableHash(key) & mask;
102 i = hash; 108 i = hash;
103 do { 109 do {
104 Word k = table->array[i].key; 110 Word k = table->array[i].key;
@@ -191,7 +197,7 @@ Res TableGrow(Table table, Count extraCapacity)
191 for(i = 0; i < oldLength; ++i) { 197 for(i = 0; i < oldLength; ++i) {
192 if (entryIsActive(table, &oldArray[i])) { 198 if (entryIsActive(table, &oldArray[i])) {
193 TableEntry entry; 199 TableEntry entry;
194 entry = TableFind(table, oldArray[i].key, FALSE /* none deleted */); 200 entry = tableFind(table, oldArray[i].key, FALSE /* none deleted */);
195 AVER(entry != NULL); 201 AVER(entry != NULL);
196 AVER(entry->key == table->unusedKey); 202 AVER(entry->key == table->unusedKey);
197 entry->key = oldArray[i].key; 203 entry->key = oldArray[i].key;
@@ -275,7 +281,7 @@ extern void TableDestroy(Table table)
275 281
276extern Bool TableLookup(void **valueReturn, Table table, Word key) 282extern Bool TableLookup(void **valueReturn, Table table, Word key)
277{ 283{
278 TableEntry entry = TableFind(table, key, TRUE /* skip deleted */); 284 TableEntry entry = tableFind(table, key, TRUE /* skip deleted */);
279 285
280 if(entry == NULL || !entryIsActive(table, entry)) 286 if(entry == NULL || !entryIsActive(table, entry))
281 return FALSE; 287 return FALSE;
@@ -296,16 +302,16 @@ extern Res TableDefine(Table table, Word key, void *value)
296 if (table->count >= table->length * SPACEFRACTION) { 302 if (table->count >= table->length * SPACEFRACTION) {
297 Res res = TableGrow(table, 1); 303 Res res = TableGrow(table, 1);
298 if(res != ResOK) return res; 304 if(res != ResOK) return res;
299 entry = TableFind(table, key, FALSE /* no deletions yet */); 305 entry = tableFind(table, key, FALSE /* no deletions yet */);
300 AVER(entry != NULL); 306 AVER(entry != NULL);
301 if (entryIsActive(table, entry)) 307 if (entryIsActive(table, entry))
302 return ResFAIL; 308 return ResFAIL;
303 } else { 309 } else {
304 entry = TableFind(table, key, TRUE /* skip deleted */); 310 entry = tableFind(table, key, TRUE /* skip deleted */);
305 if (entry != NULL && entryIsActive(table, entry)) 311 if (entry != NULL && entryIsActive(table, entry))
306 return ResFAIL; 312 return ResFAIL;
307 /* Search again to find the best slot, deletions included. */ 313 /* Search again to find the best slot, deletions included. */
308 entry = TableFind(table, key, FALSE /* don't skip deleted */); 314 entry = tableFind(table, key, FALSE /* don't skip deleted */);
309 AVER(entry != NULL); 315 AVER(entry != NULL);
310 } 316 }
311 317
@@ -321,8 +327,12 @@ extern Res TableDefine(Table table, Word key, void *value)
321 327
322extern Res TableRedefine(Table table, Word key, void *value) 328extern Res TableRedefine(Table table, Word key, void *value)
323{ 329{
324 TableEntry entry = TableFind(table, key, TRUE /* skip deletions */); 330 TableEntry entry;
325 331
332 AVER(key != table->unusedKey);
333 AVER(key != table->deletedKey);
334
335 entry = tableFind(table, key, TRUE /* skip deletions */);
326 if (entry == NULL || !entryIsActive(table, entry)) 336 if (entry == NULL || !entryIsActive(table, entry))
327 return ResFAIL; 337 return ResFAIL;
328 AVER(entry->key == key); 338 AVER(entry->key == key);
@@ -335,8 +345,12 @@ extern Res TableRedefine(Table table, Word key, void *value)
335 345
336extern Res TableRemove(Table table, Word key) 346extern Res TableRemove(Table table, Word key)
337{ 347{
338 TableEntry entry = TableFind(table, key, TRUE); 348 TableEntry entry;
349
350 AVER(key != table->unusedKey);
351 AVER(key != table->deletedKey);
339 352
353 entry = tableFind(table, key, TRUE);
340 if (entry == NULL || !entryIsActive(table, entry)) 354 if (entry == NULL || !entryIsActive(table, entry))
341 return ResFAIL; 355 return ResFAIL;
342 entry->key = table->deletedKey; 356 entry->key = table->deletedKey;