Mercurial > hg > xemacs-beta
comparison src/elhash.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | a5df635868b2 |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* Implementation of the hash table lisp object type. | |
2 Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. | |
3 Copyright (C) 1995, 1996 Ben Wing. | |
4 Copyright (C) 1997 Free Software Foundation, Inc. | |
5 | |
6 This file is part of XEmacs. | |
7 | |
8 XEmacs is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
10 Free Software Foundation; either version 2, or (at your option) any | |
11 later version. | |
12 | |
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCNTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with XEmacs; see the file COPYING. If not, write to | |
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
21 Boston, MA 02111-1307, USA. */ | |
22 | |
23 /* Synched up with: Not in FSF. */ | |
24 | |
25 #include <config.h> | |
26 #include "lisp.h" | |
27 #include "bytecode.h" | |
28 #include "elhash.h" | |
29 | |
30 Lisp_Object Qhash_tablep; | |
31 static Lisp_Object Qhashtable, Qhash_table; | |
32 static Lisp_Object Qweakness, Qvalue; | |
33 static Lisp_Object Vall_weak_hash_tables; | |
34 static Lisp_Object Qrehash_size, Qrehash_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; | |
39 | |
40 typedef struct hentry | |
41 { | |
42 Lisp_Object key; | |
43 Lisp_Object value; | |
44 } hentry; | |
45 | |
46 struct Lisp_Hash_Table | |
47 { | |
48 struct lcrecord_header header; | |
49 size_t size; | |
50 size_t count; | |
51 size_t rehash_count; | |
52 double rehash_size; | |
53 double rehash_threshold; | |
54 size_t golden_ratio; | |
55 hash_table_hash_function_t hash_function; | |
56 hash_table_test_function_t test_function; | |
57 hentry *hentries; | |
58 enum hash_table_weakness weakness; | |
59 Lisp_Object next_weak; /* Used to chain together all of the weak | |
60 hash tables. Don't mark through this. */ | |
61 }; | |
62 typedef struct Lisp_Hash_Table Lisp_Hash_Table; | |
63 | |
64 #define HENTRY_CLEAR_P(hentry) ((*(EMACS_UINT*)(&((hentry)->key))) == 0) | |
65 #define CLEAR_HENTRY(hentry) \ | |
66 ((*(EMACS_UINT*)(&((hentry)->key))) = 0, \ | |
67 (*(EMACS_UINT*)(&((hentry)->value))) = 0) | |
68 | |
69 #define HASH_TABLE_DEFAULT_SIZE 16 | |
70 #define HASH_TABLE_DEFAULT_REHASH_SIZE 1.3 | |
71 #define HASH_TABLE_MIN_SIZE 10 | |
72 | |
73 #define HASH_CODE(key, ht) \ | |
74 (((((ht)->hash_function ? (ht)->hash_function (key) : LISP_HASH (key)) \ | |
75 * (ht)->golden_ratio) \ | |
76 % (ht)->size)) | |
77 | |
78 #define KEYS_EQUAL_P(key1, key2, testfun) \ | |
79 (EQ ((key1), (key2)) || ((testfun) && (testfun) ((key1), (key2)))) | |
80 | |
81 #define LINEAR_PROBING_LOOP(probe, entries, size) \ | |
82 for (; \ | |
83 !HENTRY_CLEAR_P (probe) || \ | |
84 (probe == entries + size ? \ | |
85 (probe = entries, !HENTRY_CLEAR_P (probe)) : 0); \ | |
86 probe++) | |
87 | |
88 #ifndef ERROR_CHECK_HASH_TABLE | |
89 # ifdef ERROR_CHECK_TYPECHECK | |
90 # define ERROR_CHECK_HASH_TABLE 1 | |
91 # else | |
92 # define ERROR_CHECK_HASH_TABLE 0 | |
93 # endif | |
94 #endif | |
95 | |
96 #if ERROR_CHECK_HASH_TABLE | |
97 static void | |
98 check_hash_table_invariants (Lisp_Hash_Table *ht) | |
99 { | |
100 assert (ht->count < ht->size); | |
101 assert (ht->count <= ht->rehash_count); | |
102 assert (ht->rehash_count < ht->size); | |
103 assert ((double) ht->count * ht->rehash_threshold - 1 <= (double) ht->rehash_count); | |
104 assert (HENTRY_CLEAR_P (ht->hentries + ht->size)); | |
105 } | |
106 #else | |
107 #define check_hash_table_invariants(ht) | |
108 #endif | |
109 | |
110 /* We use linear probing instead of double hashing, despite its lack | |
111 of blessing by Knuth and company, because, as a result of the | |
112 increasing discrepancy between CPU speeds and memory speeds, cache | |
113 behavior is becoming increasingly important, e.g: | |
114 | |
115 For a trivial loop, the penalty for non-sequential access of an array is: | |
116 - a factor of 3-4 on Pentium Pro 200 Mhz | |
117 - a factor of 10 on Ultrasparc 300 Mhz */ | |
118 | |
119 /* Return a suitable size for a hash table, with at least SIZE slots. */ | |
120 static size_t | |
121 hash_table_size (size_t requested_size) | |
122 { | |
123 /* Return some prime near, but greater than or equal to, SIZE. | |
124 Decades from the time of writing, someone will have a system large | |
125 enough that the list below will be too short... */ | |
126 static CONST size_t primes [] = | |
127 { | |
128 19, 29, 41, 59, 79, 107, 149, 197, 263, 347, 457, 599, 787, 1031, | |
129 1361, 1777, 2333, 3037, 3967, 5167, 6719, 8737, 11369, 14783, | |
130 19219, 24989, 32491, 42257, 54941, 71429, 92861, 120721, 156941, | |
131 204047, 265271, 344857, 448321, 582821, 757693, 985003, 1280519, | |
132 1664681, 2164111, 2813353, 3657361, 4754591, 6180989, 8035301, | |
133 10445899, 13579681, 17653589, 22949669, 29834603, 38784989, | |
134 50420551, 65546729, 85210757, 110774011, 144006217, 187208107, | |
135 243370577, 316381771, 411296309, 534685237, 695090819, 903618083, | |
136 1174703521, 1527114613, 1985248999, 2580823717UL, 3355070839UL | |
137 }; | |
138 /* We've heard of binary search. */ | |
139 int low, high; | |
140 for (low = 0, high = countof (primes) - 1; high - low > 1;) | |
141 { | |
142 /* Loop Invariant: size < primes [high] */ | |
143 int mid = (low + high) / 2; | |
144 if (primes [mid] < requested_size) | |
145 low = mid; | |
146 else | |
147 high = mid; | |
148 } | |
149 return primes [high]; | |
150 } | |
151 | |
152 | |
153 #if 0 /* I don't think these are needed any more. | |
154 If using the general lisp_object_equal_*() functions | |
155 causes efficiency problems, these can be resurrected. --ben */ | |
156 /* equality and hash functions for Lisp strings */ | |
157 int | |
158 lisp_string_equal (Lisp_Object str1, Lisp_Object str2) | |
159 { | |
160 /* This is wrong anyway. You can't use strcmp() on Lisp strings, | |
161 because they can contain zero characters. */ | |
162 return !strcmp ((char *) XSTRING_DATA (str1), (char *) XSTRING_DATA (str2)); | |
163 } | |
164 | |
165 static hashcode_t | |
166 lisp_string_hash (Lisp_Object obj) | |
167 { | |
168 return hash_string (XSTRING_DATA (str), XSTRING_LENGTH (str)); | |
169 } | |
170 | |
171 #endif /* 0 */ | |
172 | |
173 static int | |
174 lisp_object_eql_equal (Lisp_Object obj1, Lisp_Object obj2) | |
175 { | |
176 return EQ (obj1, obj2) || (FLOATP (obj1) && internal_equal (obj1, obj2, 0)); | |
177 } | |
178 | |
179 static hashcode_t | |
180 lisp_object_eql_hash (Lisp_Object obj) | |
181 { | |
182 return FLOATP (obj) ? internal_hash (obj, 0) : LISP_HASH (obj); | |
183 } | |
184 | |
185 static int | |
186 lisp_object_equal_equal (Lisp_Object obj1, Lisp_Object obj2) | |
187 { | |
188 return internal_equal (obj1, obj2, 0); | |
189 } | |
190 | |
191 static hashcode_t | |
192 lisp_object_equal_hash (Lisp_Object obj) | |
193 { | |
194 return internal_hash (obj, 0); | |
195 } | |
196 | |
197 | |
198 static Lisp_Object | |
199 mark_hash_table (Lisp_Object obj) | |
200 { | |
201 Lisp_Hash_Table *ht = XHASH_TABLE (obj); | |
202 | |
203 /* If the hash table is weak, we don't want to mark the keys and | |
204 values (we scan over them after everything else has been marked, | |
205 and mark or remove them as necessary). */ | |
206 if (ht->weakness == HASH_TABLE_NON_WEAK) | |
207 { | |
208 hentry *e, *sentinel; | |
209 | |
210 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | |
211 if (!HENTRY_CLEAR_P (e)) | |
212 { | |
213 mark_object (e->key); | |
214 mark_object (e->value); | |
215 } | |
216 } | |
217 return Qnil; | |
218 } | |
219 | |
220 /* Equality of hash tables. Two hash tables are equal when they are of | |
221 the same weakness and test function, they have the same number of | |
222 elements, and for each key in the hash table, the values are `equal'. | |
223 | |
224 This is similar to Common Lisp `equalp' of hash tables, with the | |
225 difference that CL requires the keys to be compared with the test | |
226 function, which we don't do. Doing that would require consing, and | |
227 consing is a bad idea in `equal'. Anyway, our method should provide | |
228 the same result -- if the keys are not equal according to the test | |
229 function, then Fgethash() in hash_table_equal_mapper() will fail. */ | |
230 static int | |
231 hash_table_equal (Lisp_Object hash_table1, Lisp_Object hash_table2, int depth) | |
232 { | |
233 Lisp_Hash_Table *ht1 = XHASH_TABLE (hash_table1); | |
234 Lisp_Hash_Table *ht2 = XHASH_TABLE (hash_table2); | |
235 hentry *e, *sentinel; | |
236 | |
237 if ((ht1->test_function != ht2->test_function) || | |
238 (ht1->weakness != ht2->weakness) || | |
239 (ht1->count != ht2->count)) | |
240 return 0; | |
241 | |
242 depth++; | |
243 | |
244 for (e = ht1->hentries, sentinel = e + ht1->size; e < sentinel; e++) | |
245 if (!HENTRY_CLEAR_P (e)) | |
246 /* Look up the key in the other hash table, and compare the values. */ | |
247 { | |
248 Lisp_Object value_in_other = Fgethash (e->key, hash_table2, Qunbound); | |
249 if (UNBOUNDP (value_in_other) || | |
250 !internal_equal (e->value, value_in_other, depth)) | |
251 return 0; /* Give up */ | |
252 } | |
253 | |
254 return 1; | |
255 } | |
256 | |
257 /* Printing hash tables. | |
258 | |
259 This is non-trivial, because we use a readable structure-style | |
260 syntax for hash tables. This means that a typical hash table will be | |
261 readably printed in the form of: | |
262 | |
263 #s(hash-table size 2 data (key1 value1 key2 value2)) | |
264 | |
265 The supported hash table structure keywords and their values are: | |
266 `test' (eql (or nil), eq or equal) | |
267 `size' (a natnum or nil) | |
268 `rehash-size' (a float) | |
269 `rehash-threshold' (a float) | |
270 `weakness' (nil, t, key or value) | |
271 `data' (a list) | |
272 | |
273 If `print-readably' is non-nil, then a simpler syntax is used; for | |
274 instance: | |
275 | |
276 #<hash-table size 2/13 data (key1 value1 key2 value2) 0x874d> | |
277 | |
278 The data is truncated to four pairs, and the rest is shown with | |
279 `...'. This printer does not cons. */ | |
280 | |
281 | |
282 /* Print the data of the hash table. This maps through a Lisp | |
283 hash table and prints key/value pairs using PRINTCHARFUN. */ | |
284 static void | |
285 print_hash_table_data (Lisp_Hash_Table *ht, Lisp_Object printcharfun) | |
286 { | |
287 int count = 0; | |
288 hentry *e, *sentinel; | |
289 | |
290 write_c_string (" data (", printcharfun); | |
291 | |
292 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | |
293 if (!HENTRY_CLEAR_P (e)) | |
294 { | |
295 if (count > 0) | |
296 write_c_string (" ", printcharfun); | |
297 if (!print_readably && count > 3) | |
298 { | |
299 write_c_string ("...", printcharfun); | |
300 break; | |
301 } | |
302 print_internal (e->key, printcharfun, 1); | |
303 write_c_string (" ", printcharfun); | |
304 print_internal (e->value, printcharfun, 1); | |
305 count++; | |
306 } | |
307 | |
308 write_c_string (")", printcharfun); | |
309 } | |
310 | |
311 static void | |
312 print_hash_table (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) | |
313 { | |
314 Lisp_Hash_Table *ht = XHASH_TABLE (obj); | |
315 char buf[128]; | |
316 | |
317 write_c_string (print_readably ? "#s(hash-table" : "#<hash-table", | |
318 printcharfun); | |
319 | |
320 /* These checks have a kludgy look to them, but they are safe. | |
321 Due to nature of hashing, you cannot use arbitrary | |
322 test functions anyway. */ | |
323 if (!ht->test_function) | |
324 write_c_string (" test eq", printcharfun); | |
325 else if (ht->test_function == lisp_object_equal_equal) | |
326 write_c_string (" test equal", printcharfun); | |
327 else if (ht->test_function == lisp_object_eql_equal) | |
328 DO_NOTHING; | |
329 else | |
330 abort (); | |
331 | |
332 if (ht->count || !print_readably) | |
333 { | |
334 if (print_readably) | |
335 sprintf (buf, " size %lu", (unsigned long) ht->count); | |
336 else | |
337 sprintf (buf, " size %lu/%lu", | |
338 (unsigned long) ht->count, | |
339 (unsigned long) ht->size); | |
340 write_c_string (buf, printcharfun); | |
341 } | |
342 | |
343 if (ht->weakness != HASH_TABLE_NON_WEAK) | |
344 { | |
345 sprintf (buf, " weakness %s", | |
346 (ht->weakness == HASH_TABLE_WEAK ? "t" : | |
347 ht->weakness == HASH_TABLE_KEY_WEAK ? "key" : | |
348 ht->weakness == HASH_TABLE_VALUE_WEAK ? "value" : | |
349 "you-d-better-not-see-this")); | |
350 write_c_string (buf, printcharfun); | |
351 } | |
352 | |
353 if (ht->count) | |
354 print_hash_table_data (ht, printcharfun); | |
355 | |
356 if (print_readably) | |
357 write_c_string (")", printcharfun); | |
358 else | |
359 { | |
360 sprintf (buf, " 0x%x>", ht->header.uid); | |
361 write_c_string (buf, printcharfun); | |
362 } | |
363 } | |
364 | |
365 static void | |
366 finalize_hash_table (void *header, int for_disksave) | |
367 { | |
368 if (!for_disksave) | |
369 { | |
370 Lisp_Hash_Table *ht = (Lisp_Hash_Table *) header; | |
371 | |
372 xfree (ht->hentries); | |
373 ht->hentries = 0; | |
374 } | |
375 } | |
376 | |
377 static const struct lrecord_description hentry_description_1[] = { | |
378 { XD_LISP_OBJECT, offsetof(hentry, key), 2 }, | |
379 { XD_END } | |
380 }; | |
381 | |
382 static const struct struct_description hentry_description = { | |
383 sizeof(hentry), | |
384 hentry_description_1 | |
385 }; | |
386 | |
387 const struct lrecord_description hash_table_description[] = { | |
388 { XD_SIZE_T, offsetof(Lisp_Hash_Table, size) }, | |
389 { XD_STRUCT_PTR, offsetof(Lisp_Hash_Table, hentries), XD_INDIRECT(0, 1), &hentry_description }, | |
390 { XD_LO_LINK, offsetof(Lisp_Hash_Table, next_weak) }, | |
391 { XD_END } | |
392 }; | |
393 | |
394 DEFINE_LRECORD_IMPLEMENTATION ("hash-table", hash_table, | |
395 mark_hash_table, print_hash_table, | |
396 finalize_hash_table, | |
397 /* #### Implement hash_table_hash()! */ | |
398 hash_table_equal, 0, | |
399 hash_table_description, | |
400 Lisp_Hash_Table); | |
401 | |
402 static Lisp_Hash_Table * | |
403 xhash_table (Lisp_Object hash_table) | |
404 { | |
405 if (!gc_in_progress) | |
406 CHECK_HASH_TABLE (hash_table); | |
407 check_hash_table_invariants (XHASH_TABLE (hash_table)); | |
408 return XHASH_TABLE (hash_table); | |
409 } | |
410 | |
411 | |
412 /************************************************************************/ | |
413 /* Creation of Hash Tables */ | |
414 /************************************************************************/ | |
415 | |
416 /* Creation of hash tables, without error-checking. */ | |
417 static double | |
418 hash_table_rehash_threshold (Lisp_Hash_Table *ht) | |
419 { | |
420 return | |
421 ht->rehash_threshold > 0.0 ? ht->rehash_threshold : | |
422 ht->size > 4096 && !ht->test_function ? 0.7 : 0.6; | |
423 } | |
424 | |
425 static void | |
426 compute_hash_table_derived_values (Lisp_Hash_Table *ht) | |
427 { | |
428 ht->rehash_count = (size_t) | |
429 ((double) ht->size * hash_table_rehash_threshold (ht)); | |
430 ht->golden_ratio = (size_t) | |
431 ((double) ht->size * (.6180339887 / (double) sizeof (Lisp_Object))); | |
432 } | |
433 | |
434 Lisp_Object | |
435 make_general_lisp_hash_table (enum hash_table_test test, | |
436 size_t size, | |
437 double rehash_size, | |
438 double rehash_threshold, | |
439 enum hash_table_weakness weakness) | |
440 { | |
441 Lisp_Object hash_table; | |
442 Lisp_Hash_Table *ht = alloc_lcrecord_type (Lisp_Hash_Table, &lrecord_hash_table); | |
443 | |
444 ht->rehash_size = rehash_size; | |
445 ht->rehash_threshold = rehash_threshold; | |
446 ht->weakness = weakness; | |
447 | |
448 switch (test) | |
449 { | |
450 case HASH_TABLE_EQ: | |
451 ht->test_function = 0; | |
452 ht->hash_function = 0; | |
453 break; | |
454 | |
455 case HASH_TABLE_EQL: | |
456 ht->test_function = lisp_object_eql_equal; | |
457 ht->hash_function = lisp_object_eql_hash; | |
458 break; | |
459 | |
460 case HASH_TABLE_EQUAL: | |
461 ht->test_function = lisp_object_equal_equal; | |
462 ht->hash_function = lisp_object_equal_hash; | |
463 break; | |
464 | |
465 default: | |
466 abort (); | |
467 } | |
468 | |
469 if (ht->rehash_size <= 0.0) | |
470 ht->rehash_size = HASH_TABLE_DEFAULT_REHASH_SIZE; | |
471 if (size < HASH_TABLE_MIN_SIZE) | |
472 size = HASH_TABLE_MIN_SIZE; | |
473 if (rehash_threshold < 0.0) | |
474 rehash_threshold = 0.75; | |
475 ht->size = | |
476 hash_table_size ((size_t) ((double) size / hash_table_rehash_threshold (ht)) + 1); | |
477 ht->count = 0; | |
478 compute_hash_table_derived_values (ht); | |
479 | |
480 /* We leave room for one never-occupied sentinel hentry at the end. */ | |
481 ht->hentries = xnew_array (hentry, ht->size + 1); | |
482 | |
483 { | |
484 hentry *e, *sentinel; | |
485 for (e = ht->hentries, sentinel = e + ht->size; e <= sentinel; e++) | |
486 CLEAR_HENTRY (e); | |
487 } | |
488 | |
489 XSETHASH_TABLE (hash_table, ht); | |
490 | |
491 if (weakness == HASH_TABLE_NON_WEAK) | |
492 ht->next_weak = Qunbound; | |
493 else | |
494 ht->next_weak = Vall_weak_hash_tables, Vall_weak_hash_tables = hash_table; | |
495 | |
496 return hash_table; | |
497 } | |
498 | |
499 Lisp_Object | |
500 make_lisp_hash_table (size_t size, | |
501 enum hash_table_weakness weakness, | |
502 enum hash_table_test test) | |
503 { | |
504 return make_general_lisp_hash_table | |
505 (test, size, HASH_TABLE_DEFAULT_REHASH_SIZE, -1.0, weakness); | |
506 } | |
507 | |
508 /* Pretty reading of hash tables. | |
509 | |
510 Here we use the existing structures mechanism (which is, | |
511 unfortunately, pretty cumbersome) for validating and instantiating | |
512 the hash tables. The idea is that the side-effect of reading a | |
513 #s(hash-table PLIST) object is creation of a hash table with desired | |
514 properties, and that the hash table is returned. */ | |
515 | |
516 /* Validation functions: each keyword provides its own validation | |
517 function. The errors should maybe be continuable, but it is | |
518 unclear how this would cope with ERRB. */ | |
519 static int | |
520 hash_table_size_validate (Lisp_Object keyword, Lisp_Object value, | |
521 Error_behavior errb) | |
522 { | |
523 if (NATNUMP (value)) | |
524 return 1; | |
525 | |
526 maybe_signal_error (Qwrong_type_argument, list2 (Qnatnump, value), | |
527 Qhash_table, errb); | |
528 return 0; | |
529 } | |
530 | |
531 static size_t | |
532 decode_hash_table_size (Lisp_Object obj) | |
533 { | |
534 return NILP (obj) ? HASH_TABLE_DEFAULT_SIZE : XINT (obj); | |
535 } | |
536 | |
537 static int | |
538 hash_table_weakness_validate (Lisp_Object keyword, Lisp_Object value, | |
539 Error_behavior errb) | |
540 { | |
541 if (EQ (value, Qnil)) return 1; | |
542 if (EQ (value, Qt)) return 1; | |
543 if (EQ (value, Qkey)) return 1; | |
544 if (EQ (value, Qvalue)) return 1; | |
545 | |
546 /* Following values are obsolete as of 19990901 in xemacs-21.2 */ | |
547 if (EQ (value, Qnon_weak)) return 1; | |
548 if (EQ (value, Qweak)) return 1; | |
549 if (EQ (value, Qkey_weak)) return 1; | |
550 if (EQ (value, Qvalue_weak)) return 1; | |
551 | |
552 maybe_signal_simple_error ("Invalid hash table weakness", | |
553 value, Qhash_table, errb); | |
554 return 0; | |
555 } | |
556 | |
557 static enum hash_table_weakness | |
558 decode_hash_table_weakness (Lisp_Object obj) | |
559 { | |
560 if (EQ (obj, Qnil)) return HASH_TABLE_NON_WEAK; | |
561 if (EQ (obj, Qt)) return HASH_TABLE_WEAK; | |
562 if (EQ (obj, Qkey)) return HASH_TABLE_KEY_WEAK; | |
563 if (EQ (obj, Qvalue)) return HASH_TABLE_VALUE_WEAK; | |
564 | |
565 /* Following values are obsolete as of 19990901 in xemacs-21.2 */ | |
566 if (EQ (obj, Qnon_weak)) return HASH_TABLE_NON_WEAK; | |
567 if (EQ (obj, Qweak)) return HASH_TABLE_WEAK; | |
568 if (EQ (obj, Qkey_weak)) return HASH_TABLE_KEY_WEAK; | |
569 if (EQ (obj, Qvalue_weak)) return HASH_TABLE_VALUE_WEAK; | |
570 | |
571 signal_simple_error ("Invalid hash table weakness", obj); | |
572 return HASH_TABLE_NON_WEAK; /* not reached */ | |
573 } | |
574 | |
575 static int | |
576 hash_table_test_validate (Lisp_Object keyword, Lisp_Object value, | |
577 Error_behavior errb) | |
578 { | |
579 if (EQ (value, Qnil)) return 1; | |
580 if (EQ (value, Qeq)) return 1; | |
581 if (EQ (value, Qequal)) return 1; | |
582 if (EQ (value, Qeql)) return 1; | |
583 | |
584 maybe_signal_simple_error ("Invalid hash table test", | |
585 value, Qhash_table, errb); | |
586 return 0; | |
587 } | |
588 | |
589 static enum hash_table_test | |
590 decode_hash_table_test (Lisp_Object obj) | |
591 { | |
592 if (EQ (obj, Qnil)) return HASH_TABLE_EQL; | |
593 if (EQ (obj, Qeq)) return HASH_TABLE_EQ; | |
594 if (EQ (obj, Qequal)) return HASH_TABLE_EQUAL; | |
595 if (EQ (obj, Qeql)) return HASH_TABLE_EQL; | |
596 | |
597 signal_simple_error ("Invalid hash table test", obj); | |
598 return HASH_TABLE_EQ; /* not reached */ | |
599 } | |
600 | |
601 static int | |
602 hash_table_rehash_size_validate (Lisp_Object keyword, Lisp_Object value, | |
603 Error_behavior errb) | |
604 { | |
605 if (!FLOATP (value)) | |
606 { | |
607 maybe_signal_error (Qwrong_type_argument, list2 (Qfloatp, value), | |
608 Qhash_table, errb); | |
609 return 0; | |
610 } | |
611 | |
612 { | |
613 double rehash_size = XFLOAT_DATA (value); | |
614 if (rehash_size <= 1.0) | |
615 { | |
616 maybe_signal_simple_error | |
617 ("Hash table rehash size must be greater than 1.0", | |
618 value, Qhash_table, errb); | |
619 return 0; | |
620 } | |
621 } | |
622 | |
623 return 1; | |
624 } | |
625 | |
626 static double | |
627 decode_hash_table_rehash_size (Lisp_Object rehash_size) | |
628 { | |
629 return NILP (rehash_size) ? -1.0 : XFLOAT_DATA (rehash_size); | |
630 } | |
631 | |
632 static int | |
633 hash_table_rehash_threshold_validate (Lisp_Object keyword, Lisp_Object value, | |
634 Error_behavior errb) | |
635 { | |
636 if (!FLOATP (value)) | |
637 { | |
638 maybe_signal_error (Qwrong_type_argument, list2 (Qfloatp, value), | |
639 Qhash_table, errb); | |
640 return 0; | |
641 } | |
642 | |
643 { | |
644 double rehash_threshold = XFLOAT_DATA (value); | |
645 if (rehash_threshold <= 0.0 || rehash_threshold >= 1.0) | |
646 { | |
647 maybe_signal_simple_error | |
648 ("Hash table rehash threshold must be between 0.0 and 1.0", | |
649 value, Qhash_table, errb); | |
650 return 0; | |
651 } | |
652 } | |
653 | |
654 return 1; | |
655 } | |
656 | |
657 static double | |
658 decode_hash_table_rehash_threshold (Lisp_Object rehash_threshold) | |
659 { | |
660 return NILP (rehash_threshold) ? -1.0 : XFLOAT_DATA (rehash_threshold); | |
661 } | |
662 | |
663 static int | |
664 hash_table_data_validate (Lisp_Object keyword, Lisp_Object value, | |
665 Error_behavior errb) | |
666 { | |
667 int len; | |
668 | |
669 GET_EXTERNAL_LIST_LENGTH (value, len); | |
670 | |
671 if (len & 1) | |
672 { | |
673 maybe_signal_simple_error | |
674 ("Hash table data must have alternating key/value pairs", | |
675 value, Qhash_table, errb); | |
676 return 0; | |
677 } | |
678 return 1; | |
679 } | |
680 | |
681 /* The actual instantiation of a hash table. This does practically no | |
682 error checking, because it relies on the fact that the paranoid | |
683 functions above have error-checked everything to the last details. | |
684 If this assumption is wrong, we will get a crash immediately (with | |
685 error-checking compiled in), and we'll know if there is a bug in | |
686 the structure mechanism. So there. */ | |
687 static Lisp_Object | |
688 hash_table_instantiate (Lisp_Object plist) | |
689 { | |
690 Lisp_Object hash_table; | |
691 Lisp_Object test = Qnil; | |
692 Lisp_Object size = Qnil; | |
693 Lisp_Object rehash_size = Qnil; | |
694 Lisp_Object rehash_threshold = Qnil; | |
695 Lisp_Object weakness = Qnil; | |
696 Lisp_Object data = Qnil; | |
697 | |
698 while (!NILP (plist)) | |
699 { | |
700 Lisp_Object key, value; | |
701 key = XCAR (plist); plist = XCDR (plist); | |
702 value = XCAR (plist); plist = XCDR (plist); | |
703 | |
704 if (EQ (key, Qtest)) test = value; | |
705 else if (EQ (key, Qsize)) size = value; | |
706 else if (EQ (key, Qrehash_size)) rehash_size = value; | |
707 else if (EQ (key, Qrehash_threshold)) rehash_threshold = value; | |
708 else if (EQ (key, Qweakness)) weakness = value; | |
709 else if (EQ (key, Qdata)) data = value; | |
710 else if (EQ (key, Qtype))/*obsolete*/ weakness = value; | |
711 else | |
712 abort (); | |
713 } | |
714 | |
715 /* Create the hash table. */ | |
716 hash_table = make_general_lisp_hash_table | |
717 (decode_hash_table_test (test), | |
718 decode_hash_table_size (size), | |
719 decode_hash_table_rehash_size (rehash_size), | |
720 decode_hash_table_rehash_threshold (rehash_threshold), | |
721 decode_hash_table_weakness (weakness)); | |
722 | |
723 /* I'm not sure whether this can GC, but better safe than sorry. */ | |
724 { | |
725 struct gcpro gcpro1; | |
726 GCPRO1 (hash_table); | |
727 | |
728 /* And fill it with data. */ | |
729 while (!NILP (data)) | |
730 { | |
731 Lisp_Object key, value; | |
732 key = XCAR (data); data = XCDR (data); | |
733 value = XCAR (data); data = XCDR (data); | |
734 Fputhash (key, value, hash_table); | |
735 } | |
736 UNGCPRO; | |
737 } | |
738 | |
739 return hash_table; | |
740 } | |
741 | |
742 static void | |
743 structure_type_create_hash_table_structure_name (Lisp_Object structure_name) | |
744 { | |
745 struct structure_type *st; | |
746 | |
747 st = define_structure_type (structure_name, 0, hash_table_instantiate); | |
748 define_structure_type_keyword (st, Qtest, hash_table_test_validate); | |
749 define_structure_type_keyword (st, Qsize, hash_table_size_validate); | |
750 define_structure_type_keyword (st, Qrehash_size, hash_table_rehash_size_validate); | |
751 define_structure_type_keyword (st, Qrehash_threshold, hash_table_rehash_threshold_validate); | |
752 define_structure_type_keyword (st, Qweakness, hash_table_weakness_validate); | |
753 define_structure_type_keyword (st, Qdata, hash_table_data_validate); | |
754 | |
755 /* obsolete as of 19990901 in xemacs-21.2 */ | |
756 define_structure_type_keyword (st, Qtype, hash_table_weakness_validate); | |
757 } | |
758 | |
759 /* Create a built-in Lisp structure type named `hash-table'. | |
760 We make #s(hashtable ...) equivalent to #s(hash-table ...), | |
761 for backward compatibility. | |
762 This is called from emacs.c. */ | |
763 void | |
764 structure_type_create_hash_table (void) | |
765 { | |
766 structure_type_create_hash_table_structure_name (Qhash_table); | |
767 structure_type_create_hash_table_structure_name (Qhashtable); /* compat */ | |
768 } | |
769 | |
770 | |
771 /************************************************************************/ | |
772 /* Definition of Lisp-visible methods */ | |
773 /************************************************************************/ | |
774 | |
775 DEFUN ("hash-table-p", Fhash_table_p, 1, 1, 0, /* | |
776 Return t if OBJECT is a hash table, else nil. | |
777 */ | |
778 (object)) | |
779 { | |
780 return HASH_TABLEP (object) ? Qt : Qnil; | |
781 } | |
782 | |
783 DEFUN ("make-hash-table", Fmake_hash_table, 0, MANY, 0, /* | |
784 Return a new empty hash table object. | |
785 Use Common Lisp style keywords to specify hash table properties. | |
786 (make-hash-table &key test size rehash-size rehash-threshold weakness) | |
787 | |
788 Keyword :test can be `eq', `eql' (default) or `equal'. | |
789 Comparison between keys is done using this function. | |
790 If speed is important, consider using `eq'. | |
791 When storing strings in the hash table, you will likely need to use `equal'. | |
792 | |
793 Keyword :size specifies the number of keys likely to be inserted. | |
794 This number of entries can be inserted without enlarging the hash table. | |
795 | |
796 Keyword :rehash-size must be a float greater than 1.0, and specifies | |
797 the factor by which to increase the size of the hash table when enlarging. | |
798 | |
799 Keyword :rehash-threshold must be a float between 0.0 and 1.0, | |
800 and specifies the load factor of the hash table which triggers enlarging. | |
801 | |
802 Non-standard keyword :weakness can be `nil' (default), `t', `key' or `value'. | |
803 | |
804 A weak hash table is one whose pointers do not count as GC referents: | |
805 for any key-value pair in the hash table, if the only remaining pointer | |
806 to either the key or the value is in a weak hash table, then the pair | |
807 will be removed from the hash table, and the key and value collected. | |
808 A non-weak hash table (or any other pointer) would prevent the object | |
809 from being collected. | |
810 | |
811 A key-weak hash table is similar to a fully-weak hash table except that | |
812 a key-value pair will be removed only if the key remains unmarked | |
813 outside of weak hash tables. The pair will remain in the hash table if | |
814 the key is pointed to by something other than a weak hash table, even | |
815 if the value is not. | |
816 | |
817 A value-weak hash table is similar to a fully-weak hash table except | |
818 that a key-value pair will be removed only if the value remains | |
819 unmarked outside of weak hash tables. The pair will remain in the | |
820 hash table if the value is pointed to by something other than a weak | |
821 hash table, even if the key is not. | |
822 */ | |
823 (int nargs, Lisp_Object *args)) | |
824 { | |
825 int i = 0; | |
826 Lisp_Object test = Qnil; | |
827 Lisp_Object size = Qnil; | |
828 Lisp_Object rehash_size = Qnil; | |
829 Lisp_Object rehash_threshold = Qnil; | |
830 Lisp_Object weakness = Qnil; | |
831 | |
832 while (i + 1 < nargs) | |
833 { | |
834 Lisp_Object keyword = args[i++]; | |
835 Lisp_Object value = args[i++]; | |
836 | |
837 if (EQ (keyword, Q_test)) test = value; | |
838 else if (EQ (keyword, Q_size)) size = value; | |
839 else if (EQ (keyword, Q_rehash_size)) rehash_size = value; | |
840 else if (EQ (keyword, Q_rehash_threshold)) rehash_threshold = value; | |
841 else if (EQ (keyword, Q_weakness)) weakness = value; | |
842 else if (EQ (keyword, Q_type))/*obsolete*/ weakness = value; | |
843 else signal_simple_error ("Invalid hash table property keyword", keyword); | |
844 } | |
845 | |
846 if (i < nargs) | |
847 signal_simple_error ("Hash table property requires a value", args[i]); | |
848 | |
849 #define VALIDATE_VAR(var) \ | |
850 if (!NILP (var)) hash_table_##var##_validate (Q##var, var, ERROR_ME); | |
851 | |
852 VALIDATE_VAR (test); | |
853 VALIDATE_VAR (size); | |
854 VALIDATE_VAR (rehash_size); | |
855 VALIDATE_VAR (rehash_threshold); | |
856 VALIDATE_VAR (weakness); | |
857 | |
858 return make_general_lisp_hash_table | |
859 (decode_hash_table_test (test), | |
860 decode_hash_table_size (size), | |
861 decode_hash_table_rehash_size (rehash_size), | |
862 decode_hash_table_rehash_threshold (rehash_threshold), | |
863 decode_hash_table_weakness (weakness)); | |
864 } | |
865 | |
866 DEFUN ("copy-hash-table", Fcopy_hash_table, 1, 1, 0, /* | |
867 Return a new hash table containing the same keys and values as HASH-TABLE. | |
868 The keys and values will not themselves be copied. | |
869 */ | |
870 (hash_table)) | |
871 { | |
872 CONST Lisp_Hash_Table *ht_old = xhash_table (hash_table); | |
873 Lisp_Hash_Table *ht = alloc_lcrecord_type (Lisp_Hash_Table, &lrecord_hash_table); | |
874 | |
875 copy_lcrecord (ht, ht_old); | |
876 | |
877 ht->hentries = xnew_array (hentry, ht_old->size + 1); | |
878 memcpy (ht->hentries, ht_old->hentries, (ht_old->size + 1) * sizeof (hentry)); | |
879 | |
880 XSETHASH_TABLE (hash_table, ht); | |
881 | |
882 if (! EQ (ht->next_weak, Qunbound)) | |
883 { | |
884 ht->next_weak = Vall_weak_hash_tables; | |
885 Vall_weak_hash_tables = hash_table; | |
886 } | |
887 | |
888 return hash_table; | |
889 } | |
890 | |
891 static void | |
892 resize_hash_table (Lisp_Hash_Table *ht, size_t new_size) | |
893 { | |
894 hentry *old_entries, *new_entries, *old_sentinel, *new_sentinel, *e; | |
895 size_t old_size; | |
896 | |
897 old_size = ht->size; | |
898 ht->size = new_size; | |
899 | |
900 old_entries = ht->hentries; | |
901 | |
902 ht->hentries = xnew_array (hentry, new_size + 1); | |
903 new_entries = ht->hentries; | |
904 | |
905 old_sentinel = old_entries + old_size; | |
906 new_sentinel = new_entries + new_size; | |
907 | |
908 for (e = new_entries; e <= new_sentinel; e++) | |
909 CLEAR_HENTRY (e); | |
910 | |
911 compute_hash_table_derived_values (ht); | |
912 | |
913 for (e = old_entries; e < old_sentinel; e++) | |
914 if (!HENTRY_CLEAR_P (e)) | |
915 { | |
916 hentry *probe = new_entries + HASH_CODE (e->key, ht); | |
917 LINEAR_PROBING_LOOP (probe, new_entries, new_size) | |
918 ; | |
919 *probe = *e; | |
920 } | |
921 | |
922 if (!DUMPEDP (old_entries)) | |
923 xfree (old_entries); | |
924 } | |
925 | |
926 void | |
927 reorganize_hash_table (Lisp_Hash_Table *ht) | |
928 { | |
929 resize_hash_table (ht, ht->size); | |
930 } | |
931 | |
932 static void | |
933 enlarge_hash_table (Lisp_Hash_Table *ht) | |
934 { | |
935 size_t new_size = | |
936 hash_table_size ((size_t) ((double) ht->size * ht->rehash_size)); | |
937 resize_hash_table (ht, new_size); | |
938 } | |
939 | |
940 static hentry * | |
941 find_hentry (Lisp_Object key, CONST Lisp_Hash_Table *ht) | |
942 { | |
943 hash_table_test_function_t test_function = ht->test_function; | |
944 hentry *entries = ht->hentries; | |
945 hentry *probe = entries + HASH_CODE (key, ht); | |
946 | |
947 LINEAR_PROBING_LOOP (probe, entries, ht->size) | |
948 if (KEYS_EQUAL_P (probe->key, key, test_function)) | |
949 break; | |
950 | |
951 return probe; | |
952 } | |
953 | |
954 DEFUN ("gethash", Fgethash, 2, 3, 0, /* | |
955 Find hash value for KEY in HASH-TABLE. | |
956 If there is no corresponding value, return DEFAULT (which defaults to nil). | |
957 */ | |
958 (key, hash_table, default_)) | |
959 { | |
960 CONST Lisp_Hash_Table *ht = xhash_table (hash_table); | |
961 hentry *e = find_hentry (key, ht); | |
962 | |
963 return HENTRY_CLEAR_P (e) ? default_ : e->value; | |
964 } | |
965 | |
966 DEFUN ("puthash", Fputhash, 3, 3, 0, /* | |
967 Hash KEY to VALUE in HASH-TABLE. | |
968 */ | |
969 (key, value, hash_table)) | |
970 { | |
971 Lisp_Hash_Table *ht = xhash_table (hash_table); | |
972 hentry *e = find_hentry (key, ht); | |
973 | |
974 if (!HENTRY_CLEAR_P (e)) | |
975 return e->value = value; | |
976 | |
977 e->key = key; | |
978 e->value = value; | |
979 | |
980 if (++ht->count >= ht->rehash_count) | |
981 enlarge_hash_table (ht); | |
982 | |
983 return value; | |
984 } | |
985 | |
986 /* Remove hentry pointed at by PROBE. | |
987 Subsequent entries are removed and reinserted. | |
988 We don't use tombstones - too wasteful. */ | |
989 static void | |
990 remhash_1 (Lisp_Hash_Table *ht, hentry *entries, hentry *probe) | |
991 { | |
992 size_t size = ht->size; | |
993 CLEAR_HENTRY (probe); | |
994 probe++; | |
995 ht->count--; | |
996 | |
997 LINEAR_PROBING_LOOP (probe, entries, size) | |
998 { | |
999 Lisp_Object key = probe->key; | |
1000 hentry *probe2 = entries + HASH_CODE (key, ht); | |
1001 LINEAR_PROBING_LOOP (probe2, entries, size) | |
1002 if (EQ (probe2->key, key)) | |
1003 /* hentry at probe doesn't need to move. */ | |
1004 goto continue_outer_loop; | |
1005 /* Move hentry from probe to new home at probe2. */ | |
1006 *probe2 = *probe; | |
1007 CLEAR_HENTRY (probe); | |
1008 continue_outer_loop: continue; | |
1009 } | |
1010 } | |
1011 | |
1012 DEFUN ("remhash", Fremhash, 2, 2, 0, /* | |
1013 Remove the entry for KEY from HASH-TABLE. | |
1014 Do nothing if there is no entry for KEY in HASH-TABLE. | |
1015 */ | |
1016 (key, hash_table)) | |
1017 { | |
1018 Lisp_Hash_Table *ht = xhash_table (hash_table); | |
1019 hentry *e = find_hentry (key, ht); | |
1020 | |
1021 if (HENTRY_CLEAR_P (e)) | |
1022 return Qnil; | |
1023 | |
1024 remhash_1 (ht, ht->hentries, e); | |
1025 return Qt; | |
1026 } | |
1027 | |
1028 DEFUN ("clrhash", Fclrhash, 1, 1, 0, /* | |
1029 Remove all entries from HASH-TABLE, leaving it empty. | |
1030 */ | |
1031 (hash_table)) | |
1032 { | |
1033 Lisp_Hash_Table *ht = xhash_table (hash_table); | |
1034 hentry *e, *sentinel; | |
1035 | |
1036 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | |
1037 CLEAR_HENTRY (e); | |
1038 ht->count = 0; | |
1039 | |
1040 return hash_table; | |
1041 } | |
1042 | |
1043 /************************************************************************/ | |
1044 /* Accessor Functions */ | |
1045 /************************************************************************/ | |
1046 | |
1047 DEFUN ("hash-table-count", Fhash_table_count, 1, 1, 0, /* | |
1048 Return the number of entries in HASH-TABLE. | |
1049 */ | |
1050 (hash_table)) | |
1051 { | |
1052 return make_int (xhash_table (hash_table)->count); | |
1053 } | |
1054 | |
1055 DEFUN ("hash-table-test", Fhash_table_test, 1, 1, 0, /* | |
1056 Return the test function of HASH-TABLE. | |
1057 This can be one of `eq', `eql' or `equal'. | |
1058 */ | |
1059 (hash_table)) | |
1060 { | |
1061 hash_table_test_function_t fun = xhash_table (hash_table)->test_function; | |
1062 | |
1063 return (fun == lisp_object_eql_equal ? Qeql : | |
1064 fun == lisp_object_equal_equal ? Qequal : | |
1065 Qeq); | |
1066 } | |
1067 | |
1068 DEFUN ("hash-table-size", Fhash_table_size, 1, 1, 0, /* | |
1069 Return the size of HASH-TABLE. | |
1070 This is the current number of slots in HASH-TABLE, whether occupied or not. | |
1071 */ | |
1072 (hash_table)) | |
1073 { | |
1074 return make_int (xhash_table (hash_table)->size); | |
1075 } | |
1076 | |
1077 DEFUN ("hash-table-rehash-size", Fhash_table_rehash_size, 1, 1, 0, /* | |
1078 Return the current rehash size of HASH-TABLE. | |
1079 This is a float greater than 1.0; the factor by which HASH-TABLE | |
1080 is enlarged when the rehash threshold is exceeded. | |
1081 */ | |
1082 (hash_table)) | |
1083 { | |
1084 return make_float (xhash_table (hash_table)->rehash_size); | |
1085 } | |
1086 | |
1087 DEFUN ("hash-table-rehash-threshold", Fhash_table_rehash_threshold, 1, 1, 0, /* | |
1088 Return the current rehash threshold of HASH-TABLE. | |
1089 This is a float between 0.0 and 1.0; the maximum `load factor' of HASH-TABLE, | |
1090 beyond which the HASH-TABLE is enlarged by rehashing. | |
1091 */ | |
1092 (hash_table)) | |
1093 { | |
1094 return make_float (hash_table_rehash_threshold (xhash_table (hash_table))); | |
1095 } | |
1096 | |
1097 DEFUN ("hash-table-weakness", Fhash_table_weakness, 1, 1, 0, /* | |
1098 Return the weakness of HASH-TABLE. | |
1099 This can be one of `nil', `t', `key' or `value'. | |
1100 */ | |
1101 (hash_table)) | |
1102 { | |
1103 switch (xhash_table (hash_table)->weakness) | |
1104 { | |
1105 case HASH_TABLE_WEAK: return Qt; | |
1106 case HASH_TABLE_KEY_WEAK: return Qkey; | |
1107 case HASH_TABLE_VALUE_WEAK: return Qvalue; | |
1108 default: return Qnil; | |
1109 } | |
1110 } | |
1111 | |
1112 /* obsolete as of 19990901 in xemacs-21.2 */ | |
1113 DEFUN ("hash-table-type", Fhash_table_type, 1, 1, 0, /* | |
1114 Return the type of HASH-TABLE. | |
1115 This can be one of `non-weak', `weak', `key-weak' or `value-weak'. | |
1116 */ | |
1117 (hash_table)) | |
1118 { | |
1119 switch (xhash_table (hash_table)->weakness) | |
1120 { | |
1121 case HASH_TABLE_WEAK: return Qweak; | |
1122 case HASH_TABLE_KEY_WEAK: return Qkey_weak; | |
1123 case HASH_TABLE_VALUE_WEAK: return Qvalue_weak; | |
1124 default: return Qnon_weak; | |
1125 } | |
1126 } | |
1127 | |
1128 /************************************************************************/ | |
1129 /* Mapping Functions */ | |
1130 /************************************************************************/ | |
1131 DEFUN ("maphash", Fmaphash, 2, 2, 0, /* | |
1132 Map FUNCTION over entries in HASH-TABLE, calling it with two args, | |
1133 each key and value in HASH-TABLE. | |
1134 | |
1135 FUNCTION may not modify HASH-TABLE, with the one exception that FUNCTION | |
1136 may remhash or puthash the entry currently being processed by FUNCTION. | |
1137 */ | |
1138 (function, hash_table)) | |
1139 { | |
1140 CONST Lisp_Hash_Table *ht = xhash_table (hash_table); | |
1141 CONST hentry *e, *sentinel; | |
1142 | |
1143 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | |
1144 if (!HENTRY_CLEAR_P (e)) | |
1145 { | |
1146 Lisp_Object args[3], key; | |
1147 again: | |
1148 key = e->key; | |
1149 args[0] = function; | |
1150 args[1] = key; | |
1151 args[2] = e->value; | |
1152 Ffuncall (countof (args), args); | |
1153 /* Has FUNCTION done a remhash? */ | |
1154 if (!EQ (key, e->key) && !HENTRY_CLEAR_P (e)) | |
1155 goto again; | |
1156 } | |
1157 | |
1158 return Qnil; | |
1159 } | |
1160 | |
1161 /* Map *C* function FUNCTION over the elements of a lisp hash table. */ | |
1162 void | |
1163 elisp_maphash (maphash_function_t function, | |
1164 Lisp_Object hash_table, void *extra_arg) | |
1165 { | |
1166 CONST Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); | |
1167 CONST hentry *e, *sentinel; | |
1168 | |
1169 for (e = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | |
1170 if (!HENTRY_CLEAR_P (e)) | |
1171 { | |
1172 Lisp_Object key; | |
1173 again: | |
1174 key = e->key; | |
1175 if (function (key, e->value, extra_arg)) | |
1176 return; | |
1177 /* Has FUNCTION done a remhash? */ | |
1178 if (!EQ (key, e->key) && !HENTRY_CLEAR_P (e)) | |
1179 goto again; | |
1180 } | |
1181 } | |
1182 | |
1183 /* Remove all elements of a lisp hash table satisfying *C* predicate PREDICATE. */ | |
1184 void | |
1185 elisp_map_remhash (maphash_function_t predicate, | |
1186 Lisp_Object hash_table, void *extra_arg) | |
1187 { | |
1188 Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); | |
1189 hentry *e, *entries, *sentinel; | |
1190 | |
1191 for (e = entries = ht->hentries, sentinel = e + ht->size; e < sentinel; e++) | |
1192 if (!HENTRY_CLEAR_P (e)) | |
1193 { | |
1194 again: | |
1195 if (predicate (e->key, e->value, extra_arg)) | |
1196 { | |
1197 remhash_1 (ht, entries, e); | |
1198 if (!HENTRY_CLEAR_P (e)) | |
1199 goto again; | |
1200 } | |
1201 } | |
1202 } | |
1203 | |
1204 | |
1205 /************************************************************************/ | |
1206 /* garbage collecting weak hash tables */ | |
1207 /************************************************************************/ | |
1208 | |
1209 /* Complete the marking for semi-weak hash tables. */ | |
1210 int | |
1211 finish_marking_weak_hash_tables (void) | |
1212 { | |
1213 Lisp_Object hash_table; | |
1214 int did_mark = 0; | |
1215 | |
1216 for (hash_table = Vall_weak_hash_tables; | |
1217 !NILP (hash_table); | |
1218 hash_table = XHASH_TABLE (hash_table)->next_weak) | |
1219 { | |
1220 CONST Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); | |
1221 CONST hentry *e = ht->hentries; | |
1222 CONST hentry *sentinel = e + ht->size; | |
1223 | |
1224 if (! marked_p (hash_table)) | |
1225 /* The hash table is probably garbage. Ignore it. */ | |
1226 continue; | |
1227 | |
1228 /* Now, scan over all the pairs. For all pairs that are | |
1229 half-marked, we may need to mark the other half if we're | |
1230 keeping this pair. */ | |
1231 #define MARK_OBJ(obj) \ | |
1232 do { if (!marked_p (obj)) mark_object (obj), did_mark = 1; } while (0) | |
1233 | |
1234 switch (ht->weakness) | |
1235 { | |
1236 case HASH_TABLE_KEY_WEAK: | |
1237 for (; e < sentinel; e++) | |
1238 if (!HENTRY_CLEAR_P (e)) | |
1239 if (marked_p (e->key)) | |
1240 MARK_OBJ (e->value); | |
1241 break; | |
1242 | |
1243 case HASH_TABLE_VALUE_WEAK: | |
1244 for (; e < sentinel; e++) | |
1245 if (!HENTRY_CLEAR_P (e)) | |
1246 if (marked_p (e->value)) | |
1247 MARK_OBJ (e->key); | |
1248 break; | |
1249 | |
1250 case HASH_TABLE_KEY_CAR_WEAK: | |
1251 for (; e < sentinel; e++) | |
1252 if (!HENTRY_CLEAR_P (e)) | |
1253 if (!CONSP (e->key) || marked_p (XCAR (e->key))) | |
1254 { | |
1255 MARK_OBJ (e->key); | |
1256 MARK_OBJ (e->value); | |
1257 } | |
1258 break; | |
1259 | |
1260 case HASH_TABLE_VALUE_CAR_WEAK: | |
1261 for (; e < sentinel; e++) | |
1262 if (!HENTRY_CLEAR_P (e)) | |
1263 if (!CONSP (e->value) || marked_p (XCAR (e->value))) | |
1264 { | |
1265 MARK_OBJ (e->key); | |
1266 MARK_OBJ (e->value); | |
1267 } | |
1268 break; | |
1269 | |
1270 default: | |
1271 break; | |
1272 } | |
1273 } | |
1274 | |
1275 return did_mark; | |
1276 } | |
1277 | |
1278 void | |
1279 prune_weak_hash_tables (void) | |
1280 { | |
1281 Lisp_Object hash_table, prev = Qnil; | |
1282 for (hash_table = Vall_weak_hash_tables; | |
1283 !NILP (hash_table); | |
1284 hash_table = XHASH_TABLE (hash_table)->next_weak) | |
1285 { | |
1286 if (! marked_p (hash_table)) | |
1287 { | |
1288 /* This hash table itself is garbage. Remove it from the list. */ | |
1289 if (NILP (prev)) | |
1290 Vall_weak_hash_tables = XHASH_TABLE (hash_table)->next_weak; | |
1291 else | |
1292 XHASH_TABLE (prev)->next_weak = XHASH_TABLE (hash_table)->next_weak; | |
1293 } | |
1294 else | |
1295 { | |
1296 /* Now, scan over all the pairs. Remove all of the pairs | |
1297 in which the key or value, or both, is unmarked | |
1298 (depending on the weakness of the hash table). */ | |
1299 Lisp_Hash_Table *ht = XHASH_TABLE (hash_table); | |
1300 hentry *entries = ht->hentries; | |
1301 hentry *sentinel = entries + ht->size; | |
1302 hentry *e; | |
1303 | |
1304 for (e = entries; e < sentinel; e++) | |
1305 if (!HENTRY_CLEAR_P (e)) | |
1306 { | |
1307 again: | |
1308 if (!marked_p (e->key) || !marked_p (e->value)) | |
1309 { | |
1310 remhash_1 (ht, entries, e); | |
1311 if (!HENTRY_CLEAR_P (e)) | |
1312 goto again; | |
1313 } | |
1314 } | |
1315 | |
1316 prev = hash_table; | |
1317 } | |
1318 } | |
1319 } | |
1320 | |
1321 /* Return a hash value for an array of Lisp_Objects of size SIZE. */ | |
1322 | |
1323 hashcode_t | |
1324 internal_array_hash (Lisp_Object *arr, int size, int depth) | |
1325 { | |
1326 int i; | |
1327 unsigned long hash = 0; | |
1328 | |
1329 if (size <= 5) | |
1330 { | |
1331 for (i = 0; i < size; i++) | |
1332 hash = HASH2 (hash, internal_hash (arr[i], depth + 1)); | |
1333 return hash; | |
1334 } | |
1335 | |
1336 /* just pick five elements scattered throughout the array. | |
1337 A slightly better approach would be to offset by some | |
1338 noise factor from the points chosen below. */ | |
1339 for (i = 0; i < 5; i++) | |
1340 hash = HASH2 (hash, internal_hash (arr[i*size/5], depth + 1)); | |
1341 | |
1342 return hash; | |
1343 } | |
1344 | |
1345 /* Return a hash value for a Lisp_Object. This is for use when hashing | |
1346 objects with the comparison being `equal' (for `eq', you can just | |
1347 use the Lisp_Object itself as the hash value). You need to make a | |
1348 tradeoff between the speed of the hash function and how good the | |
1349 hashing is. In particular, the hash function needs to be FAST, | |
1350 so you can't just traipse down the whole tree hashing everything | |
1351 together. Most of the time, objects will differ in the first | |
1352 few elements you hash. Thus, we only go to a short depth (5) | |
1353 and only hash at most 5 elements out of a vector. Theoretically | |
1354 we could still take 5^5 time (a big big number) to compute a | |
1355 hash, but practically this won't ever happen. */ | |
1356 | |
1357 hashcode_t | |
1358 internal_hash (Lisp_Object obj, int depth) | |
1359 { | |
1360 if (depth > 5) | |
1361 return 0; | |
1362 if (CONSP (obj)) | |
1363 { | |
1364 /* no point in worrying about tail recursion, since we're not | |
1365 going very deep */ | |
1366 return HASH2 (internal_hash (XCAR (obj), depth + 1), | |
1367 internal_hash (XCDR (obj), depth + 1)); | |
1368 } | |
1369 if (STRINGP (obj)) | |
1370 { | |
1371 return hash_string (XSTRING_DATA (obj), XSTRING_LENGTH (obj)); | |
1372 } | |
1373 if (VECTORP (obj)) | |
1374 { | |
1375 return HASH2 (XVECTOR_LENGTH (obj), | |
1376 internal_array_hash (XVECTOR_DATA (obj), | |
1377 XVECTOR_LENGTH (obj), | |
1378 depth + 1)); | |
1379 } | |
1380 if (LRECORDP (obj)) | |
1381 { | |
1382 CONST struct lrecord_implementation | |
1383 *imp = XRECORD_LHEADER_IMPLEMENTATION (obj); | |
1384 if (imp->hash) | |
1385 return imp->hash (obj, depth); | |
1386 } | |
1387 | |
1388 return LISP_HASH (obj); | |
1389 } | |
1390 | |
1391 DEFUN ("sxhash", Fsxhash, 1, 1, 0, /* | |
1392 Return a hash value for OBJECT. | |
1393 (equal obj1 obj2) implies (= (sxhash obj1) (sxhash obj2)). | |
1394 */ | |
1395 (object)) | |
1396 { | |
1397 return make_int (internal_hash (object, 0)); | |
1398 } | |
1399 | |
1400 #if 0 | |
1401 xxDEFUN ("internal-hash-value", Finternal_hash_value, 1, 1, 0, /* | |
1402 Hash value of OBJECT. For debugging. | |
1403 The value is returned as (HIGH . LOW). | |
1404 */ | |
1405 (object)) | |
1406 { | |
1407 /* This function is pretty 32bit-centric. */ | |
1408 unsigned long hash = internal_hash (object, 0); | |
1409 return Fcons (hash >> 16, hash & 0xffff); | |
1410 } | |
1411 #endif | |
1412 | |
1413 | |
1414 /************************************************************************/ | |
1415 /* initialization */ | |
1416 /************************************************************************/ | |
1417 | |
1418 void | |
1419 syms_of_elhash (void) | |
1420 { | |
1421 DEFSUBR (Fhash_table_p); | |
1422 DEFSUBR (Fmake_hash_table); | |
1423 DEFSUBR (Fcopy_hash_table); | |
1424 DEFSUBR (Fgethash); | |
1425 DEFSUBR (Fremhash); | |
1426 DEFSUBR (Fputhash); | |
1427 DEFSUBR (Fclrhash); | |
1428 DEFSUBR (Fmaphash); | |
1429 DEFSUBR (Fhash_table_count); | |
1430 DEFSUBR (Fhash_table_test); | |
1431 DEFSUBR (Fhash_table_size); | |
1432 DEFSUBR (Fhash_table_rehash_size); | |
1433 DEFSUBR (Fhash_table_rehash_threshold); | |
1434 DEFSUBR (Fhash_table_weakness); | |
1435 DEFSUBR (Fhash_table_type); /* obsolete */ | |
1436 DEFSUBR (Fsxhash); | |
1437 #if 0 | |
1438 DEFSUBR (Finternal_hash_value); | |
1439 #endif | |
1440 | |
1441 defsymbol (&Qhash_tablep, "hash-table-p"); | |
1442 defsymbol (&Qhash_table, "hash-table"); | |
1443 defsymbol (&Qhashtable, "hashtable"); | |
1444 defsymbol (&Qweakness, "weakness"); | |
1445 defsymbol (&Qvalue, "value"); | |
1446 defsymbol (&Qrehash_size, "rehash-size"); | |
1447 defsymbol (&Qrehash_threshold, "rehash-threshold"); | |
1448 | |
1449 defsymbol (&Qweak, "weak"); /* obsolete */ | |
1450 defsymbol (&Qkey_weak, "key-weak"); /* obsolete */ | |
1451 defsymbol (&Qvalue_weak, "value-weak"); /* obsolete */ | |
1452 defsymbol (&Qnon_weak, "non-weak"); /* obsolete */ | |
1453 | |
1454 defkeyword (&Q_test, ":test"); | |
1455 defkeyword (&Q_size, ":size"); | |
1456 defkeyword (&Q_rehash_size, ":rehash-size"); | |
1457 defkeyword (&Q_rehash_threshold, ":rehash-threshold"); | |
1458 defkeyword (&Q_weakness, ":weakness"); | |
1459 defkeyword (&Q_type, ":type"); /* obsolete */ | |
1460 } | |
1461 | |
1462 void | |
1463 vars_of_elhash (void) | |
1464 { | |
1465 /* This must NOT be staticpro'd */ | |
1466 Vall_weak_hash_tables = Qnil; | |
1467 pdump_wire_list (&Vall_weak_hash_tables); | |
1468 } |