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 {