Mercurial > hg > xemacs-beta
comparison src/elhash.c @ 223:2c611d1463a6 r20-4b10
Import from CVS: tag r20-4b10
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:10:54 +0200 |
parents | 78478c60bfcd |
children | 557eaa0339bf |
comparison
equal
deleted
inserted
replaced
222:aae4c8b01452 | 223:2c611d1463a6 |
---|---|
1 /* Lisp interface to hash tables. | 1 /* Lisp interface to hash tables. |
2 Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. | 2 Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. |
3 Copyright (C) 1995, 1996 Ben Wing. | 3 Copyright (C) 1995, 1996 Ben Wing. |
4 Copyright (C) 1997 Free Software Foundation, Inc. | |
4 | 5 |
5 This file is part of XEmacs. | 6 This file is part of XEmacs. |
6 | 7 |
7 XEmacs is free software; you can redistribute it and/or modify it | 8 XEmacs is free software; you can redistribute it and/or modify it |
8 under the terms of the GNU General Public License as published by the | 9 under the terms of the GNU General Public License as published by the |
25 #include "lisp.h" | 26 #include "lisp.h" |
26 #include "hash.h" | 27 #include "hash.h" |
27 #include "elhash.h" | 28 #include "elhash.h" |
28 #include "bytecode.h" | 29 #include "bytecode.h" |
29 | 30 |
30 Lisp_Object Qhashtablep; | 31 Lisp_Object Qhashtablep, Qhashtable; |
32 Lisp_Object Qweak, Qkey_weak, Qvalue_weak, Qnon_weak; | |
31 | 33 |
32 #define LISP_OBJECTS_PER_HENTRY (sizeof (hentry) / sizeof (Lisp_Object))/* 2 */ | 34 #define LISP_OBJECTS_PER_HENTRY (sizeof (hentry) / sizeof (Lisp_Object))/* 2 */ |
33 | 35 |
34 struct hashtable | 36 struct hashtable |
35 { | 37 { |
67 return Qnil; | 69 return Qnil; |
68 } | 70 } |
69 ((markobj) (table->zero_entry)); | 71 ((markobj) (table->zero_entry)); |
70 return table->harray; | 72 return table->harray; |
71 } | 73 } |
74 | |
75 /* Printing hashtables. | |
76 | |
77 This is non-trivial, because we use a readable structure-style | |
78 syntax for hashtables. This means that a typical hashtable will be | |
79 readably printed in the form of: | |
80 | |
81 #s(hashtable size 2 data (key1 value1 key2 value2)) | |
82 | |
83 The supported keywords are `type' (non-weak (or nil), weak, | |
84 key-weak and value-weak), `test' (eql (or nil), eq or equal), | |
85 `size' (a natnum or nil) and `data' (a list). | |
86 | |
87 If `print-readably' is non-nil, then a simpler syntax is used; for | |
88 instance: | |
89 | |
90 #<hashtable size 2/13 data (key1 value1 key2 value2) 0x874d> | |
91 | |
92 The data is truncated to four pairs, and the rest is shown with | |
93 `...'. The actual printer is non-consing. */ | |
94 | |
95 struct print_mapper_arg { | |
96 EMACS_INT count; /* Used to implement the truncation | |
97 for non-readable printing, as well | |
98 as to avoid the unnecessary space | |
99 at the beginning. */ | |
100 Lisp_Object printcharfun; | |
101 }; | |
102 | |
103 static void | |
104 print_hashtable_data_mapper (void *key, void *contents, void *arg) | |
105 { | |
106 Lisp_Object keytem, valuetem; | |
107 struct print_mapper_arg *closure = (struct print_mapper_arg *)arg; | |
108 | |
109 if (closure->count < 4 || print_readably) | |
110 { | |
111 CVOID_TO_LISP (keytem, key); | |
112 CVOID_TO_LISP (valuetem, contents); | |
113 | |
114 if (closure->count) | |
115 write_c_string (" ", closure->printcharfun); | |
116 | |
117 print_internal (keytem, closure->printcharfun, 1); | |
118 write_c_string (" ", closure->printcharfun); | |
119 print_internal (valuetem, closure->printcharfun, 1); | |
120 } | |
121 ++closure->count; | |
122 } | |
123 | |
124 /* Print the data of the hashtable. This maps through a Lisp | |
125 hashtable and prints key/value pairs using PRINTCHARFUN. */ | |
126 static void | |
127 print_hashtable_data (Lisp_Object hashtable, Lisp_Object printcharfun) | |
128 { | |
129 struct print_mapper_arg closure; | |
130 closure.count = 0; | |
131 closure.printcharfun = printcharfun; | |
132 | |
133 write_c_string (" data (", printcharfun); | |
134 elisp_maphash (print_hashtable_data_mapper, hashtable, &closure); | |
135 write_c_string ((!print_readably && closure.count > 4) ? " ...)" : ")", | |
136 printcharfun); | |
137 } | |
138 | |
139 /* Needed for tests. */ | |
140 static int lisp_object_eql_equal (CONST void *x1, CONST void *x2); | |
141 static int lisp_object_equal_equal (CONST void *x1, CONST void *x2); | |
72 | 142 |
73 static void | 143 static void |
74 print_hashtable (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) | 144 print_hashtable (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) |
75 { | 145 { |
76 struct hashtable *table = XHASHTABLE (obj); | 146 struct hashtable *table = XHASHTABLE (obj); |
77 char buf[200]; | 147 char buf[128]; |
148 | |
149 write_c_string (print_readably ? "#s(hashtable" : "#<hashtable", | |
150 printcharfun); | |
151 if (table->type != HASHTABLE_NONWEAK) | |
152 { | |
153 sprintf (buf, " type %s", | |
154 (table->type == HASHTABLE_WEAK ? "weak" : | |
155 table->type == HASHTABLE_KEY_WEAK ? "key-weak" : | |
156 table->type == HASHTABLE_VALUE_WEAK ? "value-weak" : | |
157 "you-d-better-not-see-this")); | |
158 write_c_string (buf, printcharfun); | |
159 } | |
160 /* These checks are way kludgy... */ | |
161 if (table->test_function == NULL) | |
162 write_c_string (" test eq", printcharfun); | |
163 else if (table->test_function == lisp_object_equal_equal) | |
164 write_c_string (" test equal", printcharfun); | |
165 else if (table->test_function == lisp_object_eql_equal) | |
166 ; | |
167 else | |
168 abort (); | |
169 if (table->fullness || !print_readably) | |
170 { | |
171 if (print_readably) | |
172 sprintf (buf, " size %d", table->fullness); | |
173 else | |
174 sprintf (buf, " size %u/%ld", table->fullness, | |
175 XVECTOR_LENGTH (table->harray) / LISP_OBJECTS_PER_HENTRY); | |
176 write_c_string (buf, printcharfun); | |
177 } | |
178 if (table->fullness) | |
179 print_hashtable_data (obj, printcharfun); | |
78 if (print_readably) | 180 if (print_readably) |
79 error ("printing unreadable object #<hashtable 0x%x>", | 181 write_c_string (")", printcharfun); |
80 table->header.uid); | 182 else |
81 sprintf (buf, GETTEXT ("#<%shashtable %d/%ld 0x%x>"), | 183 { |
82 (table->type == HASHTABLE_WEAK ? "weak " : | 184 sprintf (buf, " 0x%x>", table->header.uid); |
83 table->type == HASHTABLE_KEY_WEAK ? "key-weak " : | 185 write_c_string (buf, printcharfun); |
84 table->type == HASHTABLE_VALUE_WEAK ? "value-weak " : | 186 } |
85 table->type == HASHTABLE_KEY_CAR_WEAK ? "key-car-weak " : | 187 } |
86 table->type == HASHTABLE_VALUE_CAR_WEAK ? "value-car-weak " : | 188 |
87 ""), | 189 |
88 table->fullness, | 190 /* Pretty reading of hashtables. |
89 XVECTOR_LENGTH (table->harray) / LISP_OBJECTS_PER_HENTRY, | 191 |
90 table->header.uid); | 192 Here we use the existing structures mechanism (which is, |
91 write_c_string (buf, printcharfun); | 193 unfortunately, pretty cumbersome) for validating and instantiating |
92 } | 194 the hashtables. The idea is that the side-effect of reading a |
93 | 195 #s(hashtable PLIST) object is creation of a hashtable with desired |
196 properties, and that the hashtable is returned. */ | |
197 | |
198 /* Validation functions: each keyword provides its own validation | |
199 function. The errors should maybe be continuable, but it is | |
200 unclear how this would cope with ERRB. */ | |
201 static int | |
202 hashtable_type_validate (Lisp_Object keyword, Lisp_Object value, | |
203 Error_behavior errb) | |
204 { | |
205 if (!(NILP (value) | |
206 || EQ (value, Qnon_weak) | |
207 || EQ (value, Qweak) | |
208 || EQ (value, Qkey_weak) | |
209 || EQ (value, Qvalue_weak))) | |
210 { | |
211 maybe_signal_simple_error ("Invalid hashtable type", value, | |
212 Qhashtable, errb); | |
213 return 0; | |
214 } | |
215 return 1; | |
216 } | |
217 | |
218 static int | |
219 hashtable_test_validate (Lisp_Object keyword, Lisp_Object value, | |
220 Error_behavior errb) | |
221 { | |
222 if (!(NILP (value) | |
223 || EQ (value, Qeq) | |
224 || EQ (value, Qeql) | |
225 || EQ (value, Qequal))) | |
226 { | |
227 maybe_signal_simple_error ("Invalid hashtable test", value, | |
228 Qhashtable, errb); | |
229 return 0; | |
230 } | |
231 return 1; | |
232 } | |
233 | |
234 static int | |
235 hashtable_size_validate (Lisp_Object keyword, Lisp_Object value, | |
236 Error_behavior errb) | |
237 { | |
238 if (!NATNUMP (value)) | |
239 { | |
240 maybe_signal_error (Qwrong_type_argument, list2 (Qnatnump, value), | |
241 Qhashtable, errb); | |
242 return 0; | |
243 } | |
244 return 1; | |
245 } | |
246 | |
247 static int | |
248 hashtable_data_validate (Lisp_Object keyword, Lisp_Object value, | |
249 Error_behavior errb) | |
250 { | |
251 int num = 0; | |
252 Lisp_Object tail; | |
253 | |
254 /* #### Doesn't respect ERRB! */ | |
255 EXTERNAL_LIST_LOOP (tail, value) | |
256 { | |
257 ++num; | |
258 QUIT; | |
259 } | |
260 if (num & 1) | |
261 { | |
262 maybe_signal_simple_error | |
263 ("Hashtable data must have alternating keyword/value pairs", value, | |
264 Qhashtable, errb); | |
265 return 0; | |
266 } | |
267 return 1; | |
268 } | |
269 | |
270 /* The actual instantiation of hashtable. This does practically no | |
271 error checking, because it relies on the fact that the paranoid | |
272 functions above have error-checked everything to the last details. | |
273 If this assumption is wrong, we will get a crash immediately (with | |
274 error-checking compiled in), and we'll know if there is a bug in | |
275 the structure mechanism. So there. */ | |
276 static Lisp_Object | |
277 hashtable_instantiate (Lisp_Object plist) | |
278 { | |
279 /* I'm not sure whether this can GC, but better safe than sorry. */ | |
280 Lisp_Object hashtab = Qnil; | |
281 Lisp_Object type = Qnil, test = Qnil, size = Qnil, data = Qnil; | |
282 Lisp_Object key, value; | |
283 struct gcpro gcpro1; | |
284 GCPRO1 (hashtab); | |
285 | |
286 while (!NILP (plist)) | |
287 { | |
288 key = XCAR (plist); | |
289 plist = XCDR (plist); | |
290 value = XCAR (plist); | |
291 plist = XCDR (plist); | |
292 if (EQ (key, Qtype)) | |
293 type = value; | |
294 else if (EQ (key, Qtest)) | |
295 test = value; | |
296 else if (EQ (key, Qsize)) | |
297 size = value; | |
298 else if (EQ (key, Qdata)) | |
299 data = value; | |
300 else | |
301 abort (); | |
302 } | |
303 if (NILP (type)) | |
304 type = Qnon_weak; | |
305 if (NILP (size)) | |
306 { | |
307 /* Divide by two, because data is a plist. */ | |
308 XSETINT (size, XINT (Flength (data)) / 2); | |
309 } | |
310 | |
311 /* Create the hashtable. */ | |
312 if (EQ (type, Qnon_weak)) | |
313 hashtab = Fmake_hashtable (size, test); | |
314 else if (EQ (type, Qweak)) | |
315 hashtab = Fmake_weak_hashtable (size, test); | |
316 else if (EQ (type, Qkey_weak)) | |
317 hashtab = Fmake_key_weak_hashtable (size, test); | |
318 else if (EQ (type, Qvalue_weak)) | |
319 hashtab = Fmake_value_weak_hashtable (size, test); | |
320 else | |
321 abort (); | |
322 | |
323 /* And fill it with data. */ | |
324 while (!NILP (data)) | |
325 { | |
326 key = XCAR (data); | |
327 data = XCDR (data); | |
328 value = XCAR (data); | |
329 data = XCDR (data); | |
330 Fputhash (key, value, hashtab); | |
331 } | |
332 | |
333 UNGCPRO; | |
334 return hashtab; | |
335 } | |
336 | |
337 /* Initialize the hashtable as a structure type. This is called from | |
338 emacs.c. */ | |
339 void | |
340 structure_type_create_hashtable (void) | |
341 { | |
342 struct structure_type *st; | |
343 | |
344 st = define_structure_type (Qhashtable, 0, hashtable_instantiate); | |
345 define_structure_type_keyword (st, Qtype, hashtable_type_validate); | |
346 define_structure_type_keyword (st, Qtest, hashtable_test_validate); | |
347 define_structure_type_keyword (st, Qsize, hashtable_size_validate); | |
348 define_structure_type_keyword (st, Qdata, hashtable_data_validate); | |
349 } | |
350 | |
351 /* Basic conversion and allocation functions. */ | |
352 | |
353 /* Create a C hashtable from the data in the Lisp hashtable. The | |
354 actual vector is not copied, nor are the keys or values copied. */ | |
94 static void | 355 static void |
95 ht_copy_to_c (struct hashtable *ht, c_hashtable c_table) | 356 ht_copy_to_c (struct hashtable *ht, c_hashtable c_table) |
96 { | 357 { |
97 int len = XVECTOR_LENGTH (ht->harray); | 358 int len = XVECTOR_LENGTH (ht->harray); |
98 | 359 |
451 | 712 |
452 | 713 |
453 static void | 714 static void |
454 verify_function (Lisp_Object function, CONST char *description) | 715 verify_function (Lisp_Object function, CONST char *description) |
455 { | 716 { |
717 /* #### Unused DESCRIPTION? */ | |
456 if (SYMBOLP (function)) | 718 if (SYMBOLP (function)) |
457 { | 719 { |
458 if (NILP (function)) | 720 if (NILP (function)) |
459 return; | 721 return; |
460 else | 722 else |
462 } | 724 } |
463 if (SUBRP (function) || COMPILED_FUNCTIONP (function)) | 725 if (SUBRP (function) || COMPILED_FUNCTIONP (function)) |
464 return; | 726 return; |
465 else if (CONSP (function)) | 727 else if (CONSP (function)) |
466 { | 728 { |
467 Lisp_Object funcar = Fcar (function); | 729 Lisp_Object funcar = XCAR (function); |
468 if ((SYMBOLP (funcar)) && (EQ (funcar, Qlambda) || | 730 if ((SYMBOLP (funcar)) && (EQ (funcar, Qlambda) || |
469 EQ (funcar, Qautoload))) | 731 EQ (funcar, Qautoload))) |
470 return; | 732 return; |
471 } | 733 } |
472 signal_error (Qinvalid_function, list1 (function)); | 734 signal_error (Qinvalid_function, list1 (function)); |
715 here because we know that everything *in* it is already marked, | 977 here because we know that everything *in* it is already marked, |
716 we just need to prevent the vector itself from disappearing.) | 978 we just need to prevent the vector itself from disappearing.) |
717 (The remhash above has taken care of zero_entry.) | 979 (The remhash above has taken care of zero_entry.) |
718 */ | 980 */ |
719 struct Lisp_Vector *ptr = XVECTOR (XHASHTABLE (rest)->harray); | 981 struct Lisp_Vector *ptr = XVECTOR (XHASHTABLE (rest)->harray); |
720 int len = vector_length (ptr); | |
721 #ifdef LRECORD_VECTOR | 982 #ifdef LRECORD_VECTOR |
722 if (! MARKED_RECORD_P(XHASHTABLE(rest)->harray)) | 983 if (! MARKED_RECORD_P(XHASHTABLE(rest)->harray)) |
723 { | 984 { |
724 MARK_RECORD_HEADER(&(ptr->header.lheader)); | 985 MARK_RECORD_HEADER(&(ptr->header.lheader)); |
725 did_mark = 1; | 986 did_mark = 1; |
726 } | 987 } |
727 #else | 988 #else |
989 int len = vector_length (ptr); | |
728 if (len >= 0) | 990 if (len >= 0) |
729 { | 991 { |
730 ptr->size = -1 - len; | 992 ptr->size = -1 - len; |
731 did_mark = 1; | 993 did_mark = 1; |
732 } | 994 } |
877 DEFSUBR (Fhashtable_fullness); | 1139 DEFSUBR (Fhashtable_fullness); |
878 DEFSUBR (Fmake_weak_hashtable); | 1140 DEFSUBR (Fmake_weak_hashtable); |
879 DEFSUBR (Fmake_key_weak_hashtable); | 1141 DEFSUBR (Fmake_key_weak_hashtable); |
880 DEFSUBR (Fmake_value_weak_hashtable); | 1142 DEFSUBR (Fmake_value_weak_hashtable); |
881 defsymbol (&Qhashtablep, "hashtablep"); | 1143 defsymbol (&Qhashtablep, "hashtablep"); |
1144 defsymbol (&Qhashtable, "hashtable"); | |
1145 defsymbol (&Qweak, "weak"); | |
1146 defsymbol (&Qkey_weak, "key-weak"); | |
1147 defsymbol (&Qvalue_weak, "value-weak"); | |
1148 defsymbol (&Qnon_weak, "non-weak"); | |
882 } | 1149 } |
883 | 1150 |
884 void | 1151 void |
885 vars_of_elhash (void) | 1152 vars_of_elhash (void) |
886 { | 1153 { |