diff options
| author | Richard Brooksby | 2012-09-12 23:00:33 +0100 |
|---|---|---|
| committer | Richard Brooksby | 2012-09-12 23:00:33 +0100 |
| commit | e3de034033b4614fa20dde898749d0865d442ef0 (patch) | |
| tree | 8de85cfceb0577e5459fbc4e88b976d25799ed67 /mps/code/table.c | |
| parent | 50c50c895b9c98ca0a21fe5edc86ed83d5c5ada8 (diff) | |
| download | emacs-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.c | 54 |
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 @@ | |||
| 16 | SRCID(table, "$Id$"); | 16 | SRCID(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 | ||
| 48 | typedef Word Hash; | 54 | typedef Word Hash; |
| 49 | 55 | ||
| 50 | static Hash TableHash(Word key) | 56 | static 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 | ||
| 90 | static TableEntry TableFind(Table table, Word key, Bool skip_deleted) | 96 | static 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 | ||
| 276 | extern Bool TableLookup(void **valueReturn, Table table, Word key) | 282 | extern 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 | ||
| 322 | extern Res TableRedefine(Table table, Word key, void *value) | 328 | extern 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 | ||
| 336 | extern Res TableRemove(Table table, Word key) | 346 | extern 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; |