Mercurial > hg > xemacs-beta
comparison src/elhash.c @ 398:74fd4e045ea6 r21-2-29
Import from CVS: tag r21-2-29
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:13:30 +0200 |
parents | 7d59cb494b73 |
children | a86b2b5e0111 |
comparison
equal
deleted
inserted
replaced
397:f4aeb21a5bad | 398:74fd4e045ea6 |
---|---|
25 #include <config.h> | 25 #include <config.h> |
26 #include "lisp.h" | 26 #include "lisp.h" |
27 #include "bytecode.h" | 27 #include "bytecode.h" |
28 #include "elhash.h" | 28 #include "elhash.h" |
29 | 29 |
30 Lisp_Object Qhash_tablep, Qhashtable, Qhash_table; | 30 Lisp_Object Qhash_tablep; |
31 Lisp_Object Qweak, Qkey_weak, Qvalue_weak, Qnon_weak; | 31 static Lisp_Object Qhashtable, Qhash_table; |
32 static Lisp_Object Qweakness, Qvalue; | |
32 static Lisp_Object Vall_weak_hash_tables; | 33 static Lisp_Object Vall_weak_hash_tables; |
33 static Lisp_Object Qrehash_size, Qrehash_threshold; | 34 static Lisp_Object Qrehash_size, Qrehash_threshold; |
34 static Lisp_Object Q_size, Q_test, Q_type, Q_rehash_size, Q_rehash_threshold; | 35 static Lisp_Object Q_size, Q_test, Q_weakness, Q_rehash_size, Q_rehash_threshold; |
36 | |
37 /* obsolete as of 19990901 in xemacs-21.2 */ | |
38 static Lisp_Object Qweak, Qkey_weak, Qvalue_weak, Qnon_weak, Q_type; | |
35 | 39 |
36 typedef struct hentry | 40 typedef struct hentry |
37 { | 41 { |
38 Lisp_Object key; | 42 Lisp_Object key; |
39 Lisp_Object value; | 43 Lisp_Object value; |
49 double rehash_threshold; | 53 double rehash_threshold; |
50 size_t golden_ratio; | 54 size_t golden_ratio; |
51 hash_table_hash_function_t hash_function; | 55 hash_table_hash_function_t hash_function; |
52 hash_table_test_function_t test_function; | 56 hash_table_test_function_t test_function; |
53 hentry *hentries; | 57 hentry *hentries; |
54 enum hash_table_type type; /* whether and how this hash table is weak */ | 58 enum hash_table_weakness weakness; |
55 Lisp_Object next_weak; /* Used to chain together all of the weak | 59 Lisp_Object next_weak; /* Used to chain together all of the weak |
56 hash tables. Don't mark through this. */ | 60 hash tables. Don't mark through this. */ |
57 }; | 61 }; |
58 typedef struct Lisp_Hash_Table Lisp_Hash_Table; | |
59 | 62 |
60 #define HENTRY_CLEAR_P(hentry) ((*(EMACS_UINT*)(&((hentry)->key))) == 0) | 63 #define HENTRY_CLEAR_P(hentry) ((*(EMACS_UINT*)(&((hentry)->key))) == 0) |
61 #define CLEAR_HENTRY(hentry) ((*(EMACS_UINT*)(&((hentry)->key))) = 0) | 64 #define CLEAR_HENTRY(hentry) \ |
65 ((*(EMACS_UINT*)(&((hentry)->key))) = 0, \ | |
66 (*(EMACS_UINT*)(&((hentry)->value))) = 0) | |
62 | 67 |
63 #define HASH_TABLE_DEFAULT_SIZE 16 | 68 #define HASH_TABLE_DEFAULT_SIZE 16 |
64 #define HASH_TABLE_DEFAULT_REHASH_SIZE 1.3 | 69 #define HASH_TABLE_DEFAULT_REHASH_SIZE 1.3 |
65 #define HASH_TABLE_MIN_SIZE 10 | 70 #define HASH_TABLE_MIN_SIZE 10 |
66 | 71 |
67 #define HASH_CODE(key, ht) \ | 72 #define HASH_CODE(key, ht) \ |
68 (((((ht)->hash_function ? (ht)->hash_function (key) : LISP_HASH (key)) \ | 73 ((((ht)->hash_function ? (ht)->hash_function (key) : LISP_HASH (key)) \ |
69 * (ht)->golden_ratio) \ | 74 * (ht)->golden_ratio) \ |
70 % (ht)->size)) | 75 % (ht)->size) |
71 | 76 |
72 #define KEYS_EQUAL_P(key1, key2, testfun) \ | 77 #define KEYS_EQUAL_P(key1, key2, testfun) \ |
73 (EQ ((key1), (key2)) || ((testfun) && (testfun) ((key1), (key2)))) | 78 (EQ (key1, key2) || ((testfun) && (testfun) (key1, key2))) |
74 | 79 |
75 #define LINEAR_PROBING_LOOP(probe, entries, size) \ | 80 #define LINEAR_PROBING_LOOP(probe, entries, size) \ |
76 for (; \ | 81 for (; \ |
77 !HENTRY_CLEAR_P (probe) || \ | 82 !HENTRY_CLEAR_P (probe) || \ |
78 (probe == entries + size ? \ | 83 (probe == entries + size ? \ |
115 hash_table_size (size_t requested_size) | 120 hash_table_size (size_t requested_size) |
116 { | 121 { |
117 /* Return some prime near, but greater than or equal to, SIZE. | 122 /* Return some prime near, but greater than or equal to, SIZE. |
118 Decades from the time of writing, someone will have a system large | 123 Decades from the time of writing, someone will have a system large |
119 enough that the list below will be too short... */ | 124 enough that the list below will be too short... */ |
120 static CONST size_t primes [] = | 125 static const size_t primes [] = |
121 { | 126 { |
122 19, 29, 41, 59, 79, 107, 149, 197, 263, 347, 457, 599, 787, 1031, | 127 19, 29, 41, 59, 79, 107, 149, 197, 263, 347, 457, 599, 787, 1031, |
123 1361, 1777, 2333, 3037, 3967, 5167, 6719, 8737, 11369, 14783, | 128 1361, 1777, 2333, 3037, 3967, 5167, 6719, 8737, 11369, 14783, |
124 19219, 24989, 32491, 42257, 54941, 71429, 92861, 120721, 156941, | 129 19219, 24989, 32491, 42257, 54941, 71429, 92861, 120721, 156941, |
125 204047, 265271, 344857, 448321, 582821, 757693, 985003, 1280519, | 130 204047, 265271, 344857, 448321, 582821, 757693, 985003, 1280519, |
188 return internal_hash (obj, 0); | 193 return internal_hash (obj, 0); |
189 } | 194 } |
190 | 195 |
191 | 196 |
192 static Lisp_Object | 197 static Lisp_Object |
193 mark_hash_table (Lisp_Object obj, void (*markobj) (Lisp_Object)) | 198 mark_hash_table (Lisp_Object obj) |
194 { | 199 { |
195 Lisp_Hash_Table *ht = XHASH_TABLE (obj); | 200 Lisp_Hash_Table *ht = XHASH_TABLE (obj); |
196 | 201 |
197 /* If the hash table is weak, we don't want to mark the keys and | 202 /* If the hash table is weak, we don't want to mark the keys and |
198 values (we scan over them after everything else has been marked, | 203 values (we scan over them after everything else has been marked, |
199 and mark or remove them as necessary). */ | 204 and mark or remove them as necessary). */ |
200 if (ht->type == HASH_TABLE_NON_WEAK) | 205 if (ht->weakness == HASH_TABLE_NON_WEAK) |
201 { | 206 { |
202 hentry *e, *sentinel; | 207 hentry *e, *sentinel; |
203 | 208 |
204 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | 209 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) |
205 if (!HENTRY_CLEAR_P (e)) | 210 if (!HENTRY_CLEAR_P (e)) |
206 { | 211 { |
207 markobj (e->key); | 212 mark_object (e->key); |
208 markobj (e->value); | 213 mark_object (e->value); |
209 } | 214 } |
210 } | 215 } |
211 return Qnil; | 216 return Qnil; |
212 } | 217 } |
213 | 218 |
214 /* Equality of hash tables. Two hash tables are equal when they are of | 219 /* Equality of hash tables. Two hash tables are equal when they are of |
215 the same type and test function, they have the same number of | 220 the same weakness and test function, they have the same number of |
216 elements, and for each key in the hash table, the values are `equal'. | 221 elements, and for each key in the hash table, the values are `equal'. |
217 | 222 |
218 This is similar to Common Lisp `equalp' of hash tables, with the | 223 This is similar to Common Lisp `equalp' of hash tables, with the |
219 difference that CL requires the keys to be compared with the test | 224 difference that CL requires the keys to be compared with the test |
220 function, which we don't do. Doing that would require consing, and | 225 function, which we don't do. Doing that would require consing, and |
227 Lisp_Hash_Table *ht1 = XHASH_TABLE (hash_table1); | 232 Lisp_Hash_Table *ht1 = XHASH_TABLE (hash_table1); |
228 Lisp_Hash_Table *ht2 = XHASH_TABLE (hash_table2); | 233 Lisp_Hash_Table *ht2 = XHASH_TABLE (hash_table2); |
229 hentry *e, *sentinel; | 234 hentry *e, *sentinel; |
230 | 235 |
231 if ((ht1->test_function != ht2->test_function) || | 236 if ((ht1->test_function != ht2->test_function) || |
232 (ht1->type != ht2->type) || | 237 (ht1->weakness != ht2->weakness) || |
233 (ht1->count != ht2->count)) | 238 (ht1->count != ht2->count)) |
234 return 0; | 239 return 0; |
235 | 240 |
236 depth++; | 241 depth++; |
237 | 242 |
245 return 0; /* Give up */ | 250 return 0; /* Give up */ |
246 } | 251 } |
247 | 252 |
248 return 1; | 253 return 1; |
249 } | 254 } |
255 | |
256 /* This is not a great hash function, but it _is_ correct and fast. | |
257 Examining all entries is too expensive, and examining a random | |
258 subset does not yield a correct hash function. */ | |
259 static hashcode_t | |
260 hash_table_hash (Lisp_Object hash_table, int depth) | |
261 { | |
262 return XHASH_TABLE (hash_table)->count; | |
263 } | |
264 | |
250 | 265 |
251 /* Printing hash tables. | 266 /* Printing hash tables. |
252 | 267 |
253 This is non-trivial, because we use a readable structure-style | 268 This is non-trivial, because we use a readable structure-style |
254 syntax for hash tables. This means that a typical hash table will be | 269 syntax for hash tables. This means that a typical hash table will be |
255 readably printed in the form of: | 270 readably printed in the form of: |
256 | 271 |
257 #s(hash-table size 2 data (key1 value1 key2 value2)) | 272 #s(hash-table size 2 data (key1 value1 key2 value2)) |
258 | 273 |
259 The supported keywords are `type' (non-weak (or nil), weak, | 274 The supported hash table structure keywords and their values are: |
260 key-weak and value-weak), `test' (eql (or nil), eq or equal), | 275 `test' (eql (or nil), eq or equal) |
261 `size' (a natnum or nil) and `data' (a list). | 276 `size' (a natnum or nil) |
262 | 277 `rehash-size' (a float) |
263 If `print-readably' is non-nil, then a simpler syntax is used; for | 278 `rehash-threshold' (a float) |
264 instance: | 279 `weakness' (nil, t, key or value) |
280 `data' (a list) | |
281 | |
282 If `print-readably' is nil, then a simpler syntax is used, for example | |
265 | 283 |
266 #<hash-table size 2/13 data (key1 value1 key2 value2) 0x874d> | 284 #<hash-table size 2/13 data (key1 value1 key2 value2) 0x874d> |
267 | 285 |
268 The data is truncated to four pairs, and the rest is shown with | 286 The data is truncated to four pairs, and the rest is shown with |
269 `...'. This printer does not cons. */ | 287 `...'. This printer does not cons. */ |
305 char buf[128]; | 323 char buf[128]; |
306 | 324 |
307 write_c_string (print_readably ? "#s(hash-table" : "#<hash-table", | 325 write_c_string (print_readably ? "#s(hash-table" : "#<hash-table", |
308 printcharfun); | 326 printcharfun); |
309 | 327 |
310 if (ht->type != HASH_TABLE_NON_WEAK) | |
311 { | |
312 sprintf (buf, " type %s", | |
313 (ht->type == HASH_TABLE_WEAK ? "weak" : | |
314 ht->type == HASH_TABLE_KEY_WEAK ? "key-weak" : | |
315 ht->type == HASH_TABLE_VALUE_WEAK ? "value-weak" : | |
316 "you-d-better-not-see-this")); | |
317 write_c_string (buf, printcharfun); | |
318 } | |
319 | |
320 /* These checks have a kludgy look to them, but they are safe. | 328 /* These checks have a kludgy look to them, but they are safe. |
321 Due to nature of hashing, you cannot use arbitrary | 329 Due to nature of hashing, you cannot use arbitrary |
322 test functions anyway. */ | 330 test functions anyway. */ |
323 if (!ht->test_function) | 331 if (!ht->test_function) |
324 write_c_string (" test eq", printcharfun); | 332 write_c_string (" test eq", printcharfun); |
338 (unsigned long) ht->count, | 346 (unsigned long) ht->count, |
339 (unsigned long) ht->size); | 347 (unsigned long) ht->size); |
340 write_c_string (buf, printcharfun); | 348 write_c_string (buf, printcharfun); |
341 } | 349 } |
342 | 350 |
351 if (ht->weakness != HASH_TABLE_NON_WEAK) | |
352 { | |
353 sprintf (buf, " weakness %s", | |
354 (ht->weakness == HASH_TABLE_WEAK ? "t" : | |
355 ht->weakness == HASH_TABLE_KEY_WEAK ? "key" : | |
356 ht->weakness == HASH_TABLE_VALUE_WEAK ? "value" : | |
357 "you-d-better-not-see-this")); | |
358 write_c_string (buf, printcharfun); | |
359 } | |
360 | |
343 if (ht->count) | 361 if (ht->count) |
344 print_hash_table_data (ht, printcharfun); | 362 print_hash_table_data (ht, printcharfun); |
345 | 363 |
346 if (print_readably) | 364 if (print_readably) |
347 write_c_string (")", printcharfun); | 365 write_c_string (")", printcharfun); |
362 xfree (ht->hentries); | 380 xfree (ht->hentries); |
363 ht->hentries = 0; | 381 ht->hentries = 0; |
364 } | 382 } |
365 } | 383 } |
366 | 384 |
385 static const struct lrecord_description hentry_description_1[] = { | |
386 { XD_LISP_OBJECT, offsetof (hentry, key) }, | |
387 { XD_LISP_OBJECT, offsetof (hentry, value) }, | |
388 { XD_END } | |
389 }; | |
390 | |
391 static const struct struct_description hentry_description = { | |
392 sizeof (hentry), | |
393 hentry_description_1 | |
394 }; | |
395 | |
396 const struct lrecord_description hash_table_description[] = { | |
397 { XD_SIZE_T, offsetof (Lisp_Hash_Table, size) }, | |
398 { XD_STRUCT_PTR, offsetof (Lisp_Hash_Table, hentries), XD_INDIRECT(0, 1), &hentry_description }, | |
399 { XD_LO_LINK, offsetof (Lisp_Hash_Table, next_weak) }, | |
400 { XD_END } | |
401 }; | |
402 | |
367 DEFINE_LRECORD_IMPLEMENTATION ("hash-table", hash_table, | 403 DEFINE_LRECORD_IMPLEMENTATION ("hash-table", hash_table, |
368 mark_hash_table, print_hash_table, | 404 mark_hash_table, print_hash_table, |
369 finalize_hash_table, | 405 finalize_hash_table, |
370 /* #### Implement hash_table_hash()! */ | 406 hash_table_equal, hash_table_hash, |
371 hash_table_equal, 0, | 407 hash_table_description, |
372 Lisp_Hash_Table); | 408 Lisp_Hash_Table); |
373 | 409 |
374 static Lisp_Hash_Table * | 410 static Lisp_Hash_Table * |
375 xhash_table (Lisp_Object hash_table) | 411 xhash_table (Lisp_Object hash_table) |
376 { | 412 { |
384 /************************************************************************/ | 420 /************************************************************************/ |
385 /* Creation of Hash Tables */ | 421 /* Creation of Hash Tables */ |
386 /************************************************************************/ | 422 /************************************************************************/ |
387 | 423 |
388 /* Creation of hash tables, without error-checking. */ | 424 /* Creation of hash tables, without error-checking. */ |
389 static double | |
390 hash_table_rehash_threshold (Lisp_Hash_Table *ht) | |
391 { | |
392 return | |
393 ht->rehash_threshold > 0.0 ? ht->rehash_threshold : | |
394 ht->size > 4096 && !ht->test_function ? 0.7 : 0.6; | |
395 } | |
396 | |
397 static void | 425 static void |
398 compute_hash_table_derived_values (Lisp_Hash_Table *ht) | 426 compute_hash_table_derived_values (Lisp_Hash_Table *ht) |
399 { | 427 { |
400 ht->rehash_count = (size_t) | 428 ht->rehash_count = (size_t) |
401 ((double) ht->size * hash_table_rehash_threshold (ht)); | 429 ((double) ht->size * ht->rehash_threshold); |
402 ht->golden_ratio = (size_t) | 430 ht->golden_ratio = (size_t) |
403 ((double) ht->size * (.6180339887 / (double) sizeof (Lisp_Object))); | 431 ((double) ht->size * (.6180339887 / (double) sizeof (Lisp_Object))); |
404 } | 432 } |
405 | 433 |
406 Lisp_Object | 434 Lisp_Object |
407 make_general_lisp_hash_table (size_t size, | 435 make_general_lisp_hash_table (enum hash_table_test test, |
408 enum hash_table_type type, | 436 size_t size, |
409 enum hash_table_test test, | 437 double rehash_size, |
410 double rehash_size, | 438 double rehash_threshold, |
411 double rehash_threshold) | 439 enum hash_table_weakness weakness) |
412 { | 440 { |
413 Lisp_Object hash_table; | 441 Lisp_Object hash_table; |
414 Lisp_Hash_Table *ht = alloc_lcrecord_type (Lisp_Hash_Table, lrecord_hash_table); | 442 Lisp_Hash_Table *ht = alloc_lcrecord_type (Lisp_Hash_Table, &lrecord_hash_table); |
415 | |
416 ht->type = type; | |
417 ht->rehash_size = rehash_size; | |
418 ht->rehash_threshold = rehash_threshold; | |
419 | 443 |
420 switch (test) | 444 switch (test) |
421 { | 445 { |
422 case HASH_TABLE_EQ: | 446 case HASH_TABLE_EQ: |
423 ht->test_function = 0; | 447 ht->test_function = 0; |
436 | 460 |
437 default: | 461 default: |
438 abort (); | 462 abort (); |
439 } | 463 } |
440 | 464 |
441 if (ht->rehash_size <= 0.0) | 465 ht->weakness = weakness; |
442 ht->rehash_size = HASH_TABLE_DEFAULT_REHASH_SIZE; | 466 |
467 ht->rehash_size = | |
468 rehash_size > 1.0 ? rehash_size : HASH_TABLE_DEFAULT_REHASH_SIZE; | |
469 | |
470 ht->rehash_threshold = | |
471 rehash_threshold > 0.0 ? rehash_threshold : | |
472 size > 4096 && !ht->test_function ? 0.7 : 0.6; | |
473 | |
443 if (size < HASH_TABLE_MIN_SIZE) | 474 if (size < HASH_TABLE_MIN_SIZE) |
444 size = HASH_TABLE_MIN_SIZE; | 475 size = HASH_TABLE_MIN_SIZE; |
445 if (rehash_threshold < 0.0) | 476 ht->size = hash_table_size ((size_t) (((double) size / ht->rehash_threshold) |
446 rehash_threshold = 0.75; | 477 + 1.0)); |
447 ht->size = | |
448 hash_table_size ((size_t) ((double) size / hash_table_rehash_threshold (ht)) + 1); | |
449 ht->count = 0; | 478 ht->count = 0; |
479 | |
450 compute_hash_table_derived_values (ht); | 480 compute_hash_table_derived_values (ht); |
451 | 481 |
452 /* We leave room for one never-occupied sentinel hentry at the end. */ | 482 /* We leave room for one never-occupied sentinel hentry at the end. */ |
453 ht->hentries = xnew_array (hentry, ht->size + 1); | 483 ht->hentries = xnew_array (hentry, ht->size + 1); |
454 | 484 |
458 CLEAR_HENTRY (e); | 488 CLEAR_HENTRY (e); |
459 } | 489 } |
460 | 490 |
461 XSETHASH_TABLE (hash_table, ht); | 491 XSETHASH_TABLE (hash_table, ht); |
462 | 492 |
463 if (type == HASH_TABLE_NON_WEAK) | 493 if (weakness == HASH_TABLE_NON_WEAK) |
464 ht->next_weak = Qunbound; | 494 ht->next_weak = Qunbound; |
465 else | 495 else |
466 ht->next_weak = Vall_weak_hash_tables, Vall_weak_hash_tables = hash_table; | 496 ht->next_weak = Vall_weak_hash_tables, Vall_weak_hash_tables = hash_table; |
467 | 497 |
468 return hash_table; | 498 return hash_table; |
469 } | 499 } |
470 | 500 |
471 Lisp_Object | 501 Lisp_Object |
472 make_lisp_hash_table (size_t size, | 502 make_lisp_hash_table (size_t size, |
473 enum hash_table_type type, | 503 enum hash_table_weakness weakness, |
474 enum hash_table_test test) | 504 enum hash_table_test test) |
475 { | 505 { |
476 return make_general_lisp_hash_table (size, type, test, | 506 return make_general_lisp_hash_table (test, size, -1.0, -1.0, weakness); |
477 HASH_TABLE_DEFAULT_REHASH_SIZE, -1.0); | |
478 } | 507 } |
479 | 508 |
480 /* Pretty reading of hash tables. | 509 /* Pretty reading of hash tables. |
481 | 510 |
482 Here we use the existing structures mechanism (which is, | 511 Here we use the existing structures mechanism (which is, |
505 { | 534 { |
506 return NILP (obj) ? HASH_TABLE_DEFAULT_SIZE : XINT (obj); | 535 return NILP (obj) ? HASH_TABLE_DEFAULT_SIZE : XINT (obj); |
507 } | 536 } |
508 | 537 |
509 static int | 538 static int |
510 hash_table_type_validate (Lisp_Object keyword, Lisp_Object value, | 539 hash_table_weakness_validate (Lisp_Object keyword, Lisp_Object value, |
511 Error_behavior errb) | 540 Error_behavior errb) |
512 { | 541 { |
513 if (EQ (value, Qnil)) return 1; | 542 if (EQ (value, Qnil)) return 1; |
543 if (EQ (value, Qt)) return 1; | |
544 if (EQ (value, Qkey)) return 1; | |
545 if (EQ (value, Qvalue)) return 1; | |
546 | |
547 /* Following values are obsolete as of 19990901 in xemacs-21.2 */ | |
514 if (EQ (value, Qnon_weak)) return 1; | 548 if (EQ (value, Qnon_weak)) return 1; |
515 if (EQ (value, Qweak)) return 1; | 549 if (EQ (value, Qweak)) return 1; |
516 if (EQ (value, Qkey_weak)) return 1; | 550 if (EQ (value, Qkey_weak)) return 1; |
517 if (EQ (value, Qvalue_weak)) return 1; | 551 if (EQ (value, Qvalue_weak)) return 1; |
518 | 552 |
519 maybe_signal_simple_error ("Invalid hash table type", | 553 maybe_signal_simple_error ("Invalid hash table weakness", |
520 value, Qhash_table, errb); | 554 value, Qhash_table, errb); |
521 return 0; | 555 return 0; |
522 } | 556 } |
523 | 557 |
524 static enum hash_table_type | 558 static enum hash_table_weakness |
525 decode_hash_table_type (Lisp_Object obj) | 559 decode_hash_table_weakness (Lisp_Object obj) |
526 { | 560 { |
527 if (EQ (obj, Qnil)) return HASH_TABLE_NON_WEAK; | 561 if (EQ (obj, Qnil)) return HASH_TABLE_NON_WEAK; |
562 if (EQ (obj, Qt)) return HASH_TABLE_WEAK; | |
563 if (EQ (obj, Qkey)) return HASH_TABLE_KEY_WEAK; | |
564 if (EQ (obj, Qvalue)) return HASH_TABLE_VALUE_WEAK; | |
565 | |
566 /* Following values are obsolete as of 19990901 in xemacs-21.2 */ | |
528 if (EQ (obj, Qnon_weak)) return HASH_TABLE_NON_WEAK; | 567 if (EQ (obj, Qnon_weak)) return HASH_TABLE_NON_WEAK; |
529 if (EQ (obj, Qweak)) return HASH_TABLE_WEAK; | 568 if (EQ (obj, Qweak)) return HASH_TABLE_WEAK; |
530 if (EQ (obj, Qkey_weak)) return HASH_TABLE_KEY_WEAK; | 569 if (EQ (obj, Qkey_weak)) return HASH_TABLE_KEY_WEAK; |
531 if (EQ (obj, Qvalue_weak)) return HASH_TABLE_VALUE_WEAK; | 570 if (EQ (obj, Qvalue_weak)) return HASH_TABLE_VALUE_WEAK; |
532 | 571 |
533 signal_simple_error ("Invalid hash table type", obj); | 572 signal_simple_error ("Invalid hash table weakness", obj); |
534 return HASH_TABLE_NON_WEAK; /* not reached */ | 573 return HASH_TABLE_NON_WEAK; /* not reached */ |
535 } | 574 } |
536 | 575 |
537 static int | 576 static int |
538 hash_table_test_validate (Lisp_Object keyword, Lisp_Object value, | 577 hash_table_test_validate (Lisp_Object keyword, Lisp_Object value, |
560 return HASH_TABLE_EQ; /* not reached */ | 599 return HASH_TABLE_EQ; /* not reached */ |
561 } | 600 } |
562 | 601 |
563 static int | 602 static int |
564 hash_table_rehash_size_validate (Lisp_Object keyword, Lisp_Object value, | 603 hash_table_rehash_size_validate (Lisp_Object keyword, Lisp_Object value, |
565 Error_behavior errb) | 604 Error_behavior errb) |
566 { | 605 { |
567 if (!FLOATP (value)) | 606 if (!FLOATP (value)) |
568 { | 607 { |
569 maybe_signal_error (Qwrong_type_argument, list2 (Qfloatp, value), | 608 maybe_signal_error (Qwrong_type_argument, list2 (Qfloatp, value), |
570 Qhash_table, errb); | 609 Qhash_table, errb); |
649 static Lisp_Object | 688 static Lisp_Object |
650 hash_table_instantiate (Lisp_Object plist) | 689 hash_table_instantiate (Lisp_Object plist) |
651 { | 690 { |
652 Lisp_Object hash_table; | 691 Lisp_Object hash_table; |
653 Lisp_Object test = Qnil; | 692 Lisp_Object test = Qnil; |
654 Lisp_Object type = Qnil; | |
655 Lisp_Object size = Qnil; | 693 Lisp_Object size = Qnil; |
656 Lisp_Object data = Qnil; | |
657 Lisp_Object rehash_size = Qnil; | 694 Lisp_Object rehash_size = Qnil; |
658 Lisp_Object rehash_threshold = Qnil; | 695 Lisp_Object rehash_threshold = Qnil; |
696 Lisp_Object weakness = Qnil; | |
697 Lisp_Object data = Qnil; | |
659 | 698 |
660 while (!NILP (plist)) | 699 while (!NILP (plist)) |
661 { | 700 { |
662 Lisp_Object key, value; | 701 Lisp_Object key, value; |
663 key = XCAR (plist); plist = XCDR (plist); | 702 key = XCAR (plist); plist = XCDR (plist); |
664 value = XCAR (plist); plist = XCDR (plist); | 703 value = XCAR (plist); plist = XCDR (plist); |
665 | 704 |
666 if (EQ (key, Qtest)) test = value; | 705 if (EQ (key, Qtest)) test = value; |
667 else if (EQ (key, Qtype)) type = value; | |
668 else if (EQ (key, Qsize)) size = value; | 706 else if (EQ (key, Qsize)) size = value; |
669 else if (EQ (key, Qdata)) data = value; | |
670 else if (EQ (key, Qrehash_size)) rehash_size = value; | 707 else if (EQ (key, Qrehash_size)) rehash_size = value; |
671 else if (EQ (key, Qrehash_threshold)) rehash_threshold = value; | 708 else if (EQ (key, Qrehash_threshold)) rehash_threshold = value; |
709 else if (EQ (key, Qweakness)) weakness = value; | |
710 else if (EQ (key, Qdata)) data = value; | |
711 else if (EQ (key, Qtype))/*obsolete*/ weakness = value; | |
672 else | 712 else |
673 abort (); | 713 abort (); |
674 } | 714 } |
675 | 715 |
676 /* Create the hash table. */ | 716 /* Create the hash table. */ |
677 hash_table = make_general_lisp_hash_table | 717 hash_table = make_general_lisp_hash_table |
678 (decode_hash_table_size (size), | 718 (decode_hash_table_test (test), |
679 decode_hash_table_type (type), | 719 decode_hash_table_size (size), |
680 decode_hash_table_test (test), | |
681 decode_hash_table_rehash_size (rehash_size), | 720 decode_hash_table_rehash_size (rehash_size), |
682 decode_hash_table_rehash_threshold (rehash_threshold)); | 721 decode_hash_table_rehash_threshold (rehash_threshold), |
722 decode_hash_table_weakness (weakness)); | |
683 | 723 |
684 /* I'm not sure whether this can GC, but better safe than sorry. */ | 724 /* I'm not sure whether this can GC, but better safe than sorry. */ |
685 { | 725 { |
686 struct gcpro gcpro1; | 726 struct gcpro gcpro1; |
687 GCPRO1 (hash_table); | 727 GCPRO1 (hash_table); |
704 structure_type_create_hash_table_structure_name (Lisp_Object structure_name) | 744 structure_type_create_hash_table_structure_name (Lisp_Object structure_name) |
705 { | 745 { |
706 struct structure_type *st; | 746 struct structure_type *st; |
707 | 747 |
708 st = define_structure_type (structure_name, 0, hash_table_instantiate); | 748 st = define_structure_type (structure_name, 0, hash_table_instantiate); |
749 define_structure_type_keyword (st, Qtest, hash_table_test_validate); | |
709 define_structure_type_keyword (st, Qsize, hash_table_size_validate); | 750 define_structure_type_keyword (st, Qsize, hash_table_size_validate); |
710 define_structure_type_keyword (st, Qtest, hash_table_test_validate); | |
711 define_structure_type_keyword (st, Qtype, hash_table_type_validate); | |
712 define_structure_type_keyword (st, Qdata, hash_table_data_validate); | |
713 define_structure_type_keyword (st, Qrehash_size, hash_table_rehash_size_validate); | 751 define_structure_type_keyword (st, Qrehash_size, hash_table_rehash_size_validate); |
714 define_structure_type_keyword (st, Qrehash_threshold, hash_table_rehash_threshold_validate); | 752 define_structure_type_keyword (st, Qrehash_threshold, hash_table_rehash_threshold_validate); |
753 define_structure_type_keyword (st, Qweakness, hash_table_weakness_validate); | |
754 define_structure_type_keyword (st, Qdata, hash_table_data_validate); | |
755 | |
756 /* obsolete as of 19990901 in xemacs-21.2 */ | |
757 define_structure_type_keyword (st, Qtype, hash_table_weakness_validate); | |
715 } | 758 } |
716 | 759 |
717 /* Create a built-in Lisp structure type named `hash-table'. | 760 /* Create a built-in Lisp structure type named `hash-table'. |
718 We make #s(hashtable ...) equivalent to #s(hash-table ...), | 761 We make #s(hashtable ...) equivalent to #s(hash-table ...), |
719 for backward comptabibility. | 762 for backward compatibility. |
720 This is called from emacs.c. */ | 763 This is called from emacs.c. */ |
721 void | 764 void |
722 structure_type_create_hash_table (void) | 765 structure_type_create_hash_table (void) |
723 { | 766 { |
724 structure_type_create_hash_table_structure_name (Qhash_table); | 767 structure_type_create_hash_table_structure_name (Qhash_table); |
739 } | 782 } |
740 | 783 |
741 DEFUN ("make-hash-table", Fmake_hash_table, 0, MANY, 0, /* | 784 DEFUN ("make-hash-table", Fmake_hash_table, 0, MANY, 0, /* |
742 Return a new empty hash table object. | 785 Return a new empty hash table object. |
743 Use Common Lisp style keywords to specify hash table properties. | 786 Use Common Lisp style keywords to specify hash table properties. |
744 (make-hash-table &key :size :test :type :rehash-size :rehash-threshold) | 787 (make-hash-table &key test size rehash-size rehash-threshold weakness) |
745 | |
746 Keyword :size specifies the number of keys likely to be inserted. | |
747 This number of entries can be inserted without enlarging the hash table. | |
748 | 788 |
749 Keyword :test can be `eq', `eql' (default) or `equal'. | 789 Keyword :test can be `eq', `eql' (default) or `equal'. |
750 Comparison between keys is done using this function. | 790 Comparison between keys is done using this function. |
751 If speed is important, consider using `eq'. | 791 If speed is important, consider using `eq'. |
752 When storing strings in the hash table, you will likely need to use `equal'. | 792 When storing strings in the hash table, you will likely need to use `equal'. |
753 | 793 |
754 Keyword :type can be `non-weak' (default), `weak', `key-weak' or `value-weak'. | 794 Keyword :size specifies the number of keys likely to be inserted. |
795 This number of entries can be inserted without enlarging the hash table. | |
796 | |
797 Keyword :rehash-size must be a float greater than 1.0, and specifies | |
798 the factor by which to increase the size of the hash table when enlarging. | |
799 | |
800 Keyword :rehash-threshold must be a float between 0.0 and 1.0, | |
801 and specifies the load factor of the hash table which triggers enlarging. | |
802 | |
803 Non-standard keyword :weakness can be `nil' (default), `t', `key' or `value'. | |
755 | 804 |
756 A weak hash table is one whose pointers do not count as GC referents: | 805 A weak hash table is one whose pointers do not count as GC referents: |
757 for any key-value pair in the hash table, if the only remaining pointer | 806 for any key-value pair in the hash table, if the only remaining pointer |
758 to either the key or the value is in a weak hash table, then the pair | 807 to either the key or the value is in a weak hash table, then the pair |
759 will be removed from the hash table, and the key and value collected. | 808 will be removed from the hash table, and the key and value collected. |
769 A value-weak hash table is similar to a fully-weak hash table except | 818 A value-weak hash table is similar to a fully-weak hash table except |
770 that a key-value pair will be removed only if the value remains | 819 that a key-value pair will be removed only if the value remains |
771 unmarked outside of weak hash tables. The pair will remain in the | 820 unmarked outside of weak hash tables. The pair will remain in the |
772 hash table if the value is pointed to by something other than a weak | 821 hash table if the value is pointed to by something other than a weak |
773 hash table, even if the key is not. | 822 hash table, even if the key is not. |
774 | |
775 Keyword :rehash-size must be a float greater than 1.0, and specifies | |
776 the factor by which to increase the size of the hash table when enlarging. | |
777 | |
778 Keyword :rehash-threshold must be a float between 0.0 and 1.0, | |
779 and specifies the load factor of the hash table which triggers enlarging. | |
780 | |
781 */ | 823 */ |
782 (int nargs, Lisp_Object *args)) | 824 (int nargs, Lisp_Object *args)) |
783 { | 825 { |
784 int j = 0; | 826 int i = 0; |
827 Lisp_Object test = Qnil; | |
785 Lisp_Object size = Qnil; | 828 Lisp_Object size = Qnil; |
786 Lisp_Object type = Qnil; | |
787 Lisp_Object test = Qnil; | |
788 Lisp_Object rehash_size = Qnil; | 829 Lisp_Object rehash_size = Qnil; |
789 Lisp_Object rehash_threshold = Qnil; | 830 Lisp_Object rehash_threshold = Qnil; |
790 | 831 Lisp_Object weakness = Qnil; |
791 while (j < nargs) | 832 |
792 { | 833 while (i + 1 < nargs) |
793 Lisp_Object keyword, value; | 834 { |
794 | 835 Lisp_Object keyword = args[i++]; |
795 keyword = args[j++]; | 836 Lisp_Object value = args[i++]; |
796 if (!KEYWORDP (keyword)) | 837 |
797 signal_simple_error ("Invalid hash table property keyword", keyword); | 838 if (EQ (keyword, Q_test)) test = value; |
798 if (j == nargs) | 839 else if (EQ (keyword, Q_size)) size = value; |
799 signal_simple_error ("Hash table property requires a value", keyword); | |
800 | |
801 value = args[j++]; | |
802 | |
803 if (EQ (keyword, Q_size)) size = value; | |
804 else if (EQ (keyword, Q_type)) type = value; | |
805 else if (EQ (keyword, Q_test)) test = value; | |
806 else if (EQ (keyword, Q_rehash_size)) rehash_size = value; | 840 else if (EQ (keyword, Q_rehash_size)) rehash_size = value; |
807 else if (EQ (keyword, Q_rehash_threshold)) rehash_threshold = value; | 841 else if (EQ (keyword, Q_rehash_threshold)) rehash_threshold = value; |
842 else if (EQ (keyword, Q_weakness)) weakness = value; | |
843 else if (EQ (keyword, Q_type))/*obsolete*/ weakness = value; | |
808 else signal_simple_error ("Invalid hash table property keyword", keyword); | 844 else signal_simple_error ("Invalid hash table property keyword", keyword); |
809 } | 845 } |
846 | |
847 if (i < nargs) | |
848 signal_simple_error ("Hash table property requires a value", args[i]); | |
810 | 849 |
811 #define VALIDATE_VAR(var) \ | 850 #define VALIDATE_VAR(var) \ |
812 if (!NILP (var)) hash_table_##var##_validate (Q##var, var, ERROR_ME); | 851 if (!NILP (var)) hash_table_##var##_validate (Q##var, var, ERROR_ME); |
813 | 852 |
853 VALIDATE_VAR (test); | |
814 VALIDATE_VAR (size); | 854 VALIDATE_VAR (size); |
815 VALIDATE_VAR (type); | |
816 VALIDATE_VAR (test); | |
817 VALIDATE_VAR (rehash_size); | 855 VALIDATE_VAR (rehash_size); |
818 VALIDATE_VAR (rehash_threshold); | 856 VALIDATE_VAR (rehash_threshold); |
857 VALIDATE_VAR (weakness); | |
819 | 858 |
820 return make_general_lisp_hash_table | 859 return make_general_lisp_hash_table |
821 (decode_hash_table_size (size), | 860 (decode_hash_table_test (test), |
822 decode_hash_table_type (type), | 861 decode_hash_table_size (size), |
823 decode_hash_table_test (test), | |
824 decode_hash_table_rehash_size (rehash_size), | 862 decode_hash_table_rehash_size (rehash_size), |
825 decode_hash_table_rehash_threshold (rehash_threshold)); | 863 decode_hash_table_rehash_threshold (rehash_threshold), |
864 decode_hash_table_weakness (weakness)); | |
826 } | 865 } |
827 | 866 |
828 DEFUN ("copy-hash-table", Fcopy_hash_table, 1, 1, 0, /* | 867 DEFUN ("copy-hash-table", Fcopy_hash_table, 1, 1, 0, /* |
829 Return a new hash table containing the same keys and values as HASH-TABLE. | 868 Return a new hash table containing the same keys and values as HASH-TABLE. |
830 The keys and values will not themselves be copied. | 869 The keys and values will not themselves be copied. |
831 */ | 870 */ |
832 (hash_table)) | 871 (hash_table)) |
833 { | 872 { |
834 CONST Lisp_Hash_Table *ht_old = xhash_table (hash_table); | 873 const Lisp_Hash_Table *ht_old = xhash_table (hash_table); |
835 Lisp_Hash_Table *ht = alloc_lcrecord_type (Lisp_Hash_Table, lrecord_hash_table); | 874 Lisp_Hash_Table *ht = alloc_lcrecord_type (Lisp_Hash_Table, &lrecord_hash_table); |
836 | 875 |
837 copy_lcrecord (ht, ht_old); | 876 copy_lcrecord (ht, ht_old); |
838 | 877 |
839 ht->hentries = xnew_array (hentry, ht_old->size + 1); | 878 ht->hentries = xnew_array (hentry, ht_old->size + 1); |
840 memcpy (ht->hentries, ht_old->hentries, (ht_old->size + 1) * sizeof (hentry)); | 879 memcpy (ht->hentries, ht_old->hentries, (ht_old->size + 1) * sizeof (hentry)); |
849 | 888 |
850 return hash_table; | 889 return hash_table; |
851 } | 890 } |
852 | 891 |
853 static void | 892 static void |
854 enlarge_hash_table (Lisp_Hash_Table *ht) | 893 resize_hash_table (Lisp_Hash_Table *ht, size_t new_size) |
855 { | 894 { |
856 hentry *old_entries, *new_entries, *old_sentinel, *new_sentinel, *e; | 895 hentry *old_entries, *new_entries, *sentinel, *e; |
857 size_t old_size, new_size; | 896 size_t old_size; |
858 | 897 |
859 old_size = ht->size; | 898 old_size = ht->size; |
860 new_size = ht->size = | 899 ht->size = new_size; |
861 hash_table_size ((size_t) ((double) old_size * ht->rehash_size)); | |
862 | 900 |
863 old_entries = ht->hentries; | 901 old_entries = ht->hentries; |
864 | 902 |
865 ht->hentries = xnew_array (hentry, new_size + 1); | 903 ht->hentries = xnew_array_and_zero (hentry, new_size + 1); |
866 new_entries = ht->hentries; | 904 new_entries = ht->hentries; |
867 | 905 |
868 old_sentinel = old_entries + old_size; | |
869 new_sentinel = new_entries + new_size; | |
870 | |
871 for (e = new_entries; e <= new_sentinel; e++) | |
872 CLEAR_HENTRY (e); | |
873 | |
874 compute_hash_table_derived_values (ht); | 906 compute_hash_table_derived_values (ht); |
875 | 907 |
876 for (e = old_entries; e < old_sentinel; e++) | 908 for (e = old_entries, sentinel = e + old_size; e < sentinel; e++) |
877 if (!HENTRY_CLEAR_P (e)) | 909 if (!HENTRY_CLEAR_P (e)) |
878 { | 910 { |
879 hentry *probe = new_entries + HASH_CODE (e->key, ht); | 911 hentry *probe = new_entries + HASH_CODE (e->key, ht); |
880 LINEAR_PROBING_LOOP (probe, new_entries, new_size) | 912 LINEAR_PROBING_LOOP (probe, new_entries, new_size) |
881 ; | 913 ; |
882 *probe = *e; | 914 *probe = *e; |
883 } | 915 } |
884 | 916 |
885 xfree (old_entries); | 917 if (!DUMPEDP (old_entries)) |
918 xfree (old_entries); | |
919 } | |
920 | |
921 /* After a hash table has been saved to disk and later restored by the | |
922 portable dumper, it contains the same objects, but their addresses | |
923 and thus their HASH_CODEs have changed. */ | |
924 void | |
925 pdump_reorganize_hash_table (Lisp_Object hash_table) | |
926 { | |
927 const Lisp_Hash_Table *ht = xhash_table (hash_table); | |
928 hentry *new_entries = xnew_array_and_zero (hentry, ht->size + 1); | |
929 hentry *e, *sentinel; | |
930 | |
931 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | |
932 if (!HENTRY_CLEAR_P (e)) | |
933 { | |
934 hentry *probe = new_entries + HASH_CODE (e->key, ht); | |
935 LINEAR_PROBING_LOOP (probe, new_entries, ht->size) | |
936 ; | |
937 *probe = *e; | |
938 } | |
939 | |
940 memcpy (ht->hentries, new_entries, ht->size * sizeof (hentry)); | |
941 | |
942 xfree (new_entries); | |
943 } | |
944 | |
945 static void | |
946 enlarge_hash_table (Lisp_Hash_Table *ht) | |
947 { | |
948 size_t new_size = | |
949 hash_table_size ((size_t) ((double) ht->size * ht->rehash_size)); | |
950 resize_hash_table (ht, new_size); | |
886 } | 951 } |
887 | 952 |
888 static hentry * | 953 static hentry * |
889 find_hentry (Lisp_Object key, CONST Lisp_Hash_Table *ht) | 954 find_hentry (Lisp_Object key, const Lisp_Hash_Table *ht) |
890 { | 955 { |
891 hash_table_test_function_t test_function = ht->test_function; | 956 hash_table_test_function_t test_function = ht->test_function; |
892 hentry *entries = ht->hentries; | 957 hentry *entries = ht->hentries; |
893 hentry *probe = entries + HASH_CODE (key, ht); | 958 hentry *probe = entries + HASH_CODE (key, ht); |
894 | 959 |
903 Find hash value for KEY in HASH-TABLE. | 968 Find hash value for KEY in HASH-TABLE. |
904 If there is no corresponding value, return DEFAULT (which defaults to nil). | 969 If there is no corresponding value, return DEFAULT (which defaults to nil). |
905 */ | 970 */ |
906 (key, hash_table, default_)) | 971 (key, hash_table, default_)) |
907 { | 972 { |
908 CONST Lisp_Hash_Table *ht = xhash_table (hash_table); | 973 const Lisp_Hash_Table *ht = xhash_table (hash_table); |
909 hentry *e = find_hentry (key, ht); | 974 hentry *e = find_hentry (key, ht); |
910 | 975 |
911 return HENTRY_CLEAR_P (e) ? default_ : e->value; | 976 return HENTRY_CLEAR_P (e) ? default_ : e->value; |
912 } | 977 } |
913 | 978 |
936 We don't use tombstones - too wasteful. */ | 1001 We don't use tombstones - too wasteful. */ |
937 static void | 1002 static void |
938 remhash_1 (Lisp_Hash_Table *ht, hentry *entries, hentry *probe) | 1003 remhash_1 (Lisp_Hash_Table *ht, hentry *entries, hentry *probe) |
939 { | 1004 { |
940 size_t size = ht->size; | 1005 size_t size = ht->size; |
941 CLEAR_HENTRY (probe++); | 1006 CLEAR_HENTRY (probe); |
1007 probe++; | |
942 ht->count--; | 1008 ht->count--; |
943 | 1009 |
944 LINEAR_PROBING_LOOP (probe, entries, size) | 1010 LINEAR_PROBING_LOOP (probe, entries, size) |
945 { | 1011 { |
946 Lisp_Object key = probe->key; | 1012 Lisp_Object key = probe->key; |
997 (hash_table)) | 1063 (hash_table)) |
998 { | 1064 { |
999 return make_int (xhash_table (hash_table)->count); | 1065 return make_int (xhash_table (hash_table)->count); |
1000 } | 1066 } |
1001 | 1067 |
1068 DEFUN ("hash-table-test", Fhash_table_test, 1, 1, 0, /* | |
1069 Return the test function of HASH-TABLE. | |
1070 This can be one of `eq', `eql' or `equal'. | |
1071 */ | |
1072 (hash_table)) | |
1073 { | |
1074 hash_table_test_function_t fun = xhash_table (hash_table)->test_function; | |
1075 | |
1076 return (fun == lisp_object_eql_equal ? Qeql : | |
1077 fun == lisp_object_equal_equal ? Qequal : | |
1078 Qeq); | |
1079 } | |
1080 | |
1002 DEFUN ("hash-table-size", Fhash_table_size, 1, 1, 0, /* | 1081 DEFUN ("hash-table-size", Fhash_table_size, 1, 1, 0, /* |
1003 Return the size of HASH-TABLE. | 1082 Return the size of HASH-TABLE. |
1004 This is the current number of slots in HASH-TABLE, whether occupied or not. | 1083 This is the current number of slots in HASH-TABLE, whether occupied or not. |
1005 */ | 1084 */ |
1006 (hash_table)) | 1085 (hash_table)) |
1007 { | 1086 { |
1008 return make_int (xhash_table (hash_table)->size); | 1087 return make_int (xhash_table (hash_table)->size); |
1009 } | 1088 } |
1010 | 1089 |
1090 DEFUN ("hash-table-rehash-size", Fhash_table_rehash_size, 1, 1, 0, /* | |
1091 Return the current rehash size of HASH-TABLE. | |
1092 This is a float greater than 1.0; the factor by which HASH-TABLE | |
1093 is enlarged when the rehash threshold is exceeded. | |
1094 */ | |
1095 (hash_table)) | |
1096 { | |
1097 return make_float (xhash_table (hash_table)->rehash_size); | |
1098 } | |
1099 | |
1100 DEFUN ("hash-table-rehash-threshold", Fhash_table_rehash_threshold, 1, 1, 0, /* | |
1101 Return the current rehash threshold of HASH-TABLE. | |
1102 This is a float between 0.0 and 1.0; the maximum `load factor' of HASH-TABLE, | |
1103 beyond which the HASH-TABLE is enlarged by rehashing. | |
1104 */ | |
1105 (hash_table)) | |
1106 { | |
1107 return make_float (xhash_table (hash_table)->rehash_threshold); | |
1108 } | |
1109 | |
1110 DEFUN ("hash-table-weakness", Fhash_table_weakness, 1, 1, 0, /* | |
1111 Return the weakness of HASH-TABLE. | |
1112 This can be one of `nil', `t', `key' or `value'. | |
1113 */ | |
1114 (hash_table)) | |
1115 { | |
1116 switch (xhash_table (hash_table)->weakness) | |
1117 { | |
1118 case HASH_TABLE_WEAK: return Qt; | |
1119 case HASH_TABLE_KEY_WEAK: return Qkey; | |
1120 case HASH_TABLE_VALUE_WEAK: return Qvalue; | |
1121 default: return Qnil; | |
1122 } | |
1123 } | |
1124 | |
1125 /* obsolete as of 19990901 in xemacs-21.2 */ | |
1011 DEFUN ("hash-table-type", Fhash_table_type, 1, 1, 0, /* | 1126 DEFUN ("hash-table-type", Fhash_table_type, 1, 1, 0, /* |
1012 Return the type of HASH-TABLE. | 1127 Return the type of HASH-TABLE. |
1013 This can be one of `non-weak', `weak', `key-weak' or `value-weak'. | 1128 This can be one of `non-weak', `weak', `key-weak' or `value-weak'. |
1014 */ | 1129 */ |
1015 (hash_table)) | 1130 (hash_table)) |
1016 { | 1131 { |
1017 switch (xhash_table (hash_table)->type) | 1132 switch (xhash_table (hash_table)->weakness) |
1018 { | 1133 { |
1019 case HASH_TABLE_WEAK: return Qweak; | 1134 case HASH_TABLE_WEAK: return Qweak; |
1020 case HASH_TABLE_KEY_WEAK: return Qkey_weak; | 1135 case HASH_TABLE_KEY_WEAK: return Qkey_weak; |
1021 case HASH_TABLE_VALUE_WEAK: return Qvalue_weak; | 1136 case HASH_TABLE_VALUE_WEAK: return Qvalue_weak; |
1022 default: return Qnon_weak; | 1137 default: return Qnon_weak; |
1023 } | 1138 } |
1024 } | |
1025 | |
1026 DEFUN ("hash-table-test", Fhash_table_test, 1, 1, 0, /* | |
1027 Return the test function of HASH-TABLE. | |
1028 This can be one of `eq', `eql' or `equal'. | |
1029 */ | |
1030 (hash_table)) | |
1031 { | |
1032 hash_table_test_function_t fun = xhash_table (hash_table)->test_function; | |
1033 | |
1034 return (fun == lisp_object_eql_equal ? Qeql : | |
1035 fun == lisp_object_equal_equal ? Qequal : | |
1036 Qeq); | |
1037 } | |
1038 | |
1039 DEFUN ("hash-table-rehash-size", Fhash_table_rehash_size, 1, 1, 0, /* | |
1040 Return the current rehash size of HASH-TABLE. | |
1041 This is a float greater than 1.0; the factor by which HASH-TABLE | |
1042 is enlarged when the rehash threshold is exceeded. | |
1043 */ | |
1044 (hash_table)) | |
1045 { | |
1046 return make_float (xhash_table (hash_table)->rehash_size); | |
1047 } | |
1048 | |
1049 DEFUN ("hash-table-rehash-threshold", Fhash_table_rehash_threshold, 1, 1, 0, /* | |
1050 Return the current rehash threshold of HASH-TABLE. | |
1051 This is a float between 0.0 and 1.0; the maximum `load factor' of HASH-TABLE, | |
1052 beyond which the HASH-TABLE is enlarged by rehashing. | |
1053 */ | |
1054 (hash_table)) | |
1055 { | |
1056 return make_float (hash_table_rehash_threshold (xhash_table (hash_table))); | |
1057 } | 1139 } |
1058 | 1140 |
1059 /************************************************************************/ | 1141 /************************************************************************/ |
1060 /* Mapping Functions */ | 1142 /* Mapping Functions */ |
1061 /************************************************************************/ | 1143 /************************************************************************/ |
1066 FUNCTION may not modify HASH-TABLE, with the one exception that FUNCTION | 1148 FUNCTION may not modify HASH-TABLE, with the one exception that FUNCTION |
1067 may remhash or puthash the entry currently being processed by FUNCTION. | 1149 may remhash or puthash the entry currently being processed by FUNCTION. |
1068 */ | 1150 */ |
1069 (function, hash_table)) | 1151 (function, hash_table)) |
1070 { | 1152 { |
1071 CONST Lisp_Hash_Table *ht = xhash_table (hash_table); | 1153 const Lisp_Hash_Table *ht = xhash_table (hash_table); |
1072 CONST hentry *e, *sentinel; | 1154 const hentry *e, *sentinel; |
1073 | 1155 |
1074 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | 1156 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) |
1075 if (!HENTRY_CLEAR_P (e)) | 1157 if (!HENTRY_CLEAR_P (e)) |
1076 { | 1158 { |
1077 Lisp_Object args[3], key; | 1159 Lisp_Object args[3], key; |
1092 /* Map *C* function FUNCTION over the elements of a lisp hash table. */ | 1174 /* Map *C* function FUNCTION over the elements of a lisp hash table. */ |
1093 void | 1175 void |
1094 elisp_maphash (maphash_function_t function, | 1176 elisp_maphash (maphash_function_t function, |
1095 Lisp_Object hash_table, void *extra_arg) | 1177 Lisp_Object hash_table, void *extra_arg) |
1096 { | 1178 { |
1097 CONST Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); | 1179 const Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); |
1098 CONST hentry *e, *sentinel; | 1180 const hentry *e, *sentinel; |
1099 | 1181 |
1100 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | 1182 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) |
1101 if (!HENTRY_CLEAR_P (e)) | 1183 if (!HENTRY_CLEAR_P (e)) |
1102 { | 1184 { |
1103 Lisp_Object key; | 1185 Lisp_Object key; |
1137 /* garbage collecting weak hash tables */ | 1219 /* garbage collecting weak hash tables */ |
1138 /************************************************************************/ | 1220 /************************************************************************/ |
1139 | 1221 |
1140 /* Complete the marking for semi-weak hash tables. */ | 1222 /* Complete the marking for semi-weak hash tables. */ |
1141 int | 1223 int |
1142 finish_marking_weak_hash_tables (int (*obj_marked_p) (Lisp_Object), | 1224 finish_marking_weak_hash_tables (void) |
1143 void (*markobj) (Lisp_Object)) | |
1144 { | 1225 { |
1145 Lisp_Object hash_table; | 1226 Lisp_Object hash_table; |
1146 int did_mark = 0; | 1227 int did_mark = 0; |
1147 | 1228 |
1148 for (hash_table = Vall_weak_hash_tables; | 1229 for (hash_table = Vall_weak_hash_tables; |
1149 !GC_NILP (hash_table); | 1230 !NILP (hash_table); |
1150 hash_table = XHASH_TABLE (hash_table)->next_weak) | 1231 hash_table = XHASH_TABLE (hash_table)->next_weak) |
1151 { | 1232 { |
1152 CONST Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); | 1233 const Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); |
1153 CONST hentry *e = ht->hentries; | 1234 const hentry *e = ht->hentries; |
1154 CONST hentry *sentinel = e + ht->size; | 1235 const hentry *sentinel = e + ht->size; |
1155 | 1236 |
1156 if (! obj_marked_p (hash_table)) | 1237 if (! marked_p (hash_table)) |
1157 /* The hash table is probably garbage. Ignore it. */ | 1238 /* The hash table is probably garbage. Ignore it. */ |
1158 continue; | 1239 continue; |
1159 | 1240 |
1160 /* Now, scan over all the pairs. For all pairs that are | 1241 /* Now, scan over all the pairs. For all pairs that are |
1161 half-marked, we may need to mark the other half if we're | 1242 half-marked, we may need to mark the other half if we're |
1162 keeping this pair. */ | 1243 keeping this pair. */ |
1163 #define MARK_OBJ(obj) \ | 1244 #define MARK_OBJ(obj) \ |
1164 do { if (!obj_marked_p (obj)) markobj (obj), did_mark = 1; } while (0) | 1245 do { if (!marked_p (obj)) mark_object (obj), did_mark = 1; } while (0) |
1165 | 1246 |
1166 switch (ht->type) | 1247 switch (ht->weakness) |
1167 { | 1248 { |
1168 case HASH_TABLE_KEY_WEAK: | 1249 case HASH_TABLE_KEY_WEAK: |
1169 for (; e < sentinel; e++) | 1250 for (; e < sentinel; e++) |
1170 if (!HENTRY_CLEAR_P (e)) | 1251 if (!HENTRY_CLEAR_P (e)) |
1171 if (obj_marked_p (e->key)) | 1252 if (marked_p (e->key)) |
1172 MARK_OBJ (e->value); | 1253 MARK_OBJ (e->value); |
1173 break; | 1254 break; |
1174 | 1255 |
1175 case HASH_TABLE_VALUE_WEAK: | 1256 case HASH_TABLE_VALUE_WEAK: |
1176 for (; e < sentinel; e++) | 1257 for (; e < sentinel; e++) |
1177 if (!HENTRY_CLEAR_P (e)) | 1258 if (!HENTRY_CLEAR_P (e)) |
1178 if (obj_marked_p (e->value)) | 1259 if (marked_p (e->value)) |
1179 MARK_OBJ (e->key); | 1260 MARK_OBJ (e->key); |
1180 break; | 1261 break; |
1181 | 1262 |
1182 case HASH_TABLE_KEY_CAR_WEAK: | 1263 case HASH_TABLE_KEY_CAR_WEAK: |
1183 for (; e < sentinel; e++) | 1264 for (; e < sentinel; e++) |
1184 if (!HENTRY_CLEAR_P (e)) | 1265 if (!HENTRY_CLEAR_P (e)) |
1185 if (!CONSP (e->key) || obj_marked_p (XCAR (e->key))) | 1266 if (!CONSP (e->key) || marked_p (XCAR (e->key))) |
1186 { | 1267 { |
1187 MARK_OBJ (e->key); | 1268 MARK_OBJ (e->key); |
1188 MARK_OBJ (e->value); | 1269 MARK_OBJ (e->value); |
1189 } | 1270 } |
1190 break; | 1271 break; |
1191 | 1272 |
1192 case HASH_TABLE_VALUE_CAR_WEAK: | 1273 case HASH_TABLE_VALUE_CAR_WEAK: |
1193 for (; e < sentinel; e++) | 1274 for (; e < sentinel; e++) |
1194 if (!HENTRY_CLEAR_P (e)) | 1275 if (!HENTRY_CLEAR_P (e)) |
1195 if (!CONSP (e->value) || obj_marked_p (XCAR (e->value))) | 1276 if (!CONSP (e->value) || marked_p (XCAR (e->value))) |
1196 { | 1277 { |
1197 MARK_OBJ (e->key); | 1278 MARK_OBJ (e->key); |
1198 MARK_OBJ (e->value); | 1279 MARK_OBJ (e->value); |
1199 } | 1280 } |
1200 break; | 1281 break; |
1206 | 1287 |
1207 return did_mark; | 1288 return did_mark; |
1208 } | 1289 } |
1209 | 1290 |
1210 void | 1291 void |
1211 prune_weak_hash_tables (int (*obj_marked_p) (Lisp_Object)) | 1292 prune_weak_hash_tables (void) |
1212 { | 1293 { |
1213 Lisp_Object hash_table, prev = Qnil; | 1294 Lisp_Object hash_table, prev = Qnil; |
1214 for (hash_table = Vall_weak_hash_tables; | 1295 for (hash_table = Vall_weak_hash_tables; |
1215 !GC_NILP (hash_table); | 1296 !NILP (hash_table); |
1216 hash_table = XHASH_TABLE (hash_table)->next_weak) | 1297 hash_table = XHASH_TABLE (hash_table)->next_weak) |
1217 { | 1298 { |
1218 if (! obj_marked_p (hash_table)) | 1299 if (! marked_p (hash_table)) |
1219 { | 1300 { |
1220 /* This hash table itself is garbage. Remove it from the list. */ | 1301 /* This hash table itself is garbage. Remove it from the list. */ |
1221 if (GC_NILP (prev)) | 1302 if (NILP (prev)) |
1222 Vall_weak_hash_tables = XHASH_TABLE (hash_table)->next_weak; | 1303 Vall_weak_hash_tables = XHASH_TABLE (hash_table)->next_weak; |
1223 else | 1304 else |
1224 XHASH_TABLE (prev)->next_weak = XHASH_TABLE (hash_table)->next_weak; | 1305 XHASH_TABLE (prev)->next_weak = XHASH_TABLE (hash_table)->next_weak; |
1225 } | 1306 } |
1226 else | 1307 else |
1227 { | 1308 { |
1228 /* Now, scan over all the pairs. Remove all of the pairs | 1309 /* Now, scan over all the pairs. Remove all of the pairs |
1229 in which the key or value, or both, is unmarked | 1310 in which the key or value, or both, is unmarked |
1230 (depending on the type of weak hash table). */ | 1311 (depending on the weakness of the hash table). */ |
1231 Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); | 1312 Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); |
1232 hentry *entries = ht->hentries; | 1313 hentry *entries = ht->hentries; |
1233 hentry *sentinel = entries + ht->size; | 1314 hentry *sentinel = entries + ht->size; |
1234 hentry *e; | 1315 hentry *e; |
1235 | 1316 |
1236 for (e = entries; e < sentinel; e++) | 1317 for (e = entries; e < sentinel; e++) |
1237 if (!HENTRY_CLEAR_P (e)) | 1318 if (!HENTRY_CLEAR_P (e)) |
1238 { | 1319 { |
1239 again: | 1320 again: |
1240 if (!obj_marked_p (e->key) || !obj_marked_p (e->value)) | 1321 if (!marked_p (e->key) || !marked_p (e->value)) |
1241 { | 1322 { |
1242 remhash_1 (ht, entries, e); | 1323 remhash_1 (ht, entries, e); |
1243 if (!HENTRY_CLEAR_P (e)) | 1324 if (!HENTRY_CLEAR_P (e)) |
1244 goto again; | 1325 goto again; |
1245 } | 1326 } |
1254 | 1335 |
1255 hashcode_t | 1336 hashcode_t |
1256 internal_array_hash (Lisp_Object *arr, int size, int depth) | 1337 internal_array_hash (Lisp_Object *arr, int size, int depth) |
1257 { | 1338 { |
1258 int i; | 1339 int i; |
1259 unsigned long hash = 0; | 1340 hashcode_t hash = 0; |
1341 depth++; | |
1260 | 1342 |
1261 if (size <= 5) | 1343 if (size <= 5) |
1262 { | 1344 { |
1263 for (i = 0; i < size; i++) | 1345 for (i = 0; i < size; i++) |
1264 hash = HASH2 (hash, internal_hash (arr[i], depth + 1)); | 1346 hash = HASH2 (hash, internal_hash (arr[i], depth)); |
1265 return hash; | 1347 return hash; |
1266 } | 1348 } |
1267 | 1349 |
1268 /* just pick five elements scattered throughout the array. | 1350 /* just pick five elements scattered throughout the array. |
1269 A slightly better approach would be to offset by some | 1351 A slightly better approach would be to offset by some |
1270 noise factor from the points chosen below. */ | 1352 noise factor from the points chosen below. */ |
1271 for (i = 0; i < 5; i++) | 1353 for (i = 0; i < 5; i++) |
1272 hash = HASH2 (hash, internal_hash (arr[i*size/5], depth + 1)); | 1354 hash = HASH2 (hash, internal_hash (arr[i*size/5], depth)); |
1273 | 1355 |
1274 return hash; | 1356 return hash; |
1275 } | 1357 } |
1276 | 1358 |
1277 /* Return a hash value for a Lisp_Object. This is for use when hashing | 1359 /* Return a hash value for a Lisp_Object. This is for use when hashing |
1300 } | 1382 } |
1301 if (STRINGP (obj)) | 1383 if (STRINGP (obj)) |
1302 { | 1384 { |
1303 return hash_string (XSTRING_DATA (obj), XSTRING_LENGTH (obj)); | 1385 return hash_string (XSTRING_DATA (obj), XSTRING_LENGTH (obj)); |
1304 } | 1386 } |
1305 if (VECTORP (obj)) | |
1306 { | |
1307 return HASH2 (XVECTOR_LENGTH (obj), | |
1308 internal_array_hash (XVECTOR_DATA (obj), | |
1309 XVECTOR_LENGTH (obj), | |
1310 depth + 1)); | |
1311 } | |
1312 if (LRECORDP (obj)) | 1387 if (LRECORDP (obj)) |
1313 { | 1388 { |
1314 CONST struct lrecord_implementation | 1389 const struct lrecord_implementation |
1315 *imp = XRECORD_LHEADER_IMPLEMENTATION (obj); | 1390 *imp = XRECORD_LHEADER_IMPLEMENTATION (obj); |
1316 if (imp->hash) | 1391 if (imp->hash) |
1317 return imp->hash (obj, depth); | 1392 return imp->hash (obj, depth); |
1318 } | 1393 } |
1319 | 1394 |
1320 return LISP_HASH (obj); | 1395 return LISP_HASH (obj); |
1396 } | |
1397 | |
1398 DEFUN ("sxhash", Fsxhash, 1, 1, 0, /* | |
1399 Return a hash value for OBJECT. | |
1400 (equal obj1 obj2) implies (= (sxhash obj1) (sxhash obj2)). | |
1401 */ | |
1402 (object)) | |
1403 { | |
1404 return make_int (internal_hash (object, 0)); | |
1321 } | 1405 } |
1322 | 1406 |
1323 #if 0 | 1407 #if 0 |
1324 xxDEFUN ("internal-hash-value", Finternal_hash_value, 1, 1, 0, /* | 1408 xxDEFUN ("internal-hash-value", Finternal_hash_value, 1, 1, 0, /* |
1325 Hash value of OBJECT. For debugging. | 1409 Hash value of OBJECT. For debugging. |
1326 The value is returned as (HIGH . LOW). | 1410 The value is returned as (HIGH . LOW). |
1327 */ | 1411 */ |
1328 (object)) | 1412 (object)) |
1329 { | 1413 { |
1330 /* This function is pretty 32bit-centric. */ | 1414 /* This function is pretty 32bit-centric. */ |
1331 unsigned long hash = internal_hash (object, 0); | 1415 hashcode_t hash = internal_hash (object, 0); |
1332 return Fcons (hash >> 16, hash & 0xffff); | 1416 return Fcons (hash >> 16, hash & 0xffff); |
1333 } | 1417 } |
1334 #endif | 1418 #endif |
1335 | 1419 |
1336 | 1420 |
1348 DEFSUBR (Fremhash); | 1432 DEFSUBR (Fremhash); |
1349 DEFSUBR (Fputhash); | 1433 DEFSUBR (Fputhash); |
1350 DEFSUBR (Fclrhash); | 1434 DEFSUBR (Fclrhash); |
1351 DEFSUBR (Fmaphash); | 1435 DEFSUBR (Fmaphash); |
1352 DEFSUBR (Fhash_table_count); | 1436 DEFSUBR (Fhash_table_count); |
1437 DEFSUBR (Fhash_table_test); | |
1353 DEFSUBR (Fhash_table_size); | 1438 DEFSUBR (Fhash_table_size); |
1354 DEFSUBR (Fhash_table_rehash_size); | 1439 DEFSUBR (Fhash_table_rehash_size); |
1355 DEFSUBR (Fhash_table_rehash_threshold); | 1440 DEFSUBR (Fhash_table_rehash_threshold); |
1356 DEFSUBR (Fhash_table_type); | 1441 DEFSUBR (Fhash_table_weakness); |
1357 DEFSUBR (Fhash_table_test); | 1442 DEFSUBR (Fhash_table_type); /* obsolete */ |
1443 DEFSUBR (Fsxhash); | |
1358 #if 0 | 1444 #if 0 |
1359 DEFSUBR (Finternal_hash_value); | 1445 DEFSUBR (Finternal_hash_value); |
1360 #endif | 1446 #endif |
1361 | 1447 |
1362 defsymbol (&Qhash_tablep, "hash-table-p"); | 1448 defsymbol (&Qhash_tablep, "hash-table-p"); |
1363 defsymbol (&Qhash_table, "hash-table"); | 1449 defsymbol (&Qhash_table, "hash-table"); |
1364 defsymbol (&Qhashtable, "hashtable"); | 1450 defsymbol (&Qhashtable, "hashtable"); |
1365 defsymbol (&Qweak, "weak"); | 1451 defsymbol (&Qweakness, "weakness"); |
1366 defsymbol (&Qkey_weak, "key-weak"); | 1452 defsymbol (&Qvalue, "value"); |
1367 defsymbol (&Qvalue_weak, "value-weak"); | |
1368 defsymbol (&Qnon_weak, "non-weak"); | |
1369 defsymbol (&Qrehash_size, "rehash-size"); | 1453 defsymbol (&Qrehash_size, "rehash-size"); |
1370 defsymbol (&Qrehash_threshold, "rehash-threshold"); | 1454 defsymbol (&Qrehash_threshold, "rehash-threshold"); |
1371 | 1455 |
1456 defsymbol (&Qweak, "weak"); /* obsolete */ | |
1457 defsymbol (&Qkey_weak, "key-weak"); /* obsolete */ | |
1458 defsymbol (&Qvalue_weak, "value-weak"); /* obsolete */ | |
1459 defsymbol (&Qnon_weak, "non-weak"); /* obsolete */ | |
1460 | |
1461 defkeyword (&Q_test, ":test"); | |
1372 defkeyword (&Q_size, ":size"); | 1462 defkeyword (&Q_size, ":size"); |
1373 defkeyword (&Q_test, ":test"); | |
1374 defkeyword (&Q_type, ":type"); | |
1375 defkeyword (&Q_rehash_size, ":rehash-size"); | 1463 defkeyword (&Q_rehash_size, ":rehash-size"); |
1376 defkeyword (&Q_rehash_threshold, ":rehash-threshold"); | 1464 defkeyword (&Q_rehash_threshold, ":rehash-threshold"); |
1465 defkeyword (&Q_weakness, ":weakness"); | |
1466 defkeyword (&Q_type, ":type"); /* obsolete */ | |
1377 } | 1467 } |
1378 | 1468 |
1379 void | 1469 void |
1380 vars_of_elhash (void) | 1470 vars_of_elhash (void) |
1381 { | 1471 { |
1382 /* This must NOT be staticpro'd */ | 1472 /* This must NOT be staticpro'd */ |
1383 Vall_weak_hash_tables = Qnil; | 1473 Vall_weak_hash_tables = Qnil; |
1384 } | 1474 pdump_wire_list (&Vall_weak_hash_tables); |
1475 } |