Mercurial > hg > xemacs-beta
diff src/elhash.c @ 241:f955c73f5258 r20-5b19
Import from CVS: tag r20-5b19
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:16:16 +0200 |
parents | 557eaa0339bf |
children | f220cc83d72e |
line wrap: on
line diff
--- a/src/elhash.c Mon Aug 13 10:15:49 2007 +0200 +++ b/src/elhash.c Mon Aug 13 10:16:16 2007 +0200 @@ -51,9 +51,11 @@ static Lisp_Object mark_hashtable (Lisp_Object, void (*) (Lisp_Object)); static void print_hashtable (Lisp_Object, Lisp_Object, int); static int hashtable_equal (Lisp_Object t1, Lisp_Object t2, int depth); +static unsigned long hashtable_hash (Lisp_Object obj, int depth); DEFINE_LRECORD_IMPLEMENTATION ("hashtable", hashtable, mark_hashtable, print_hashtable, 0, - hashtable_equal, 0, struct hashtable); + hashtable_equal, hashtable_hash, + struct hashtable); static Lisp_Object mark_hashtable (Lisp_Object obj, void (*markobj) (Lisp_Object)) @@ -78,43 +80,38 @@ elements, and for each key in hashtable, the values are `equal'. This is similar to Common Lisp `equalp' of hashtables, with the - difference that CL requires the keys to be compared using the - `:test' function, which we don't do. Doing that would require - consing, and consing is bad idea in `equal'. Anyway, our method - should provide the same result -- if the keys are not equal - according to `:test', then Fgethash() in hashtable_equal_mapper() - will fail. */ + difference that CL requires the keys to be compared with the test + function, which we don't do. Doing that would require consing, and + consing is bad idea in `equal'. Anyway, our method should provide + the same result -- if the keys are not equal according to test + function, then Fgethash() in hashtable_equal_mapper() will fail. */ struct hashtable_equal_closure { int depth; - int equal_so_far; + int equal; Lisp_Object other_table; }; -static void +static int hashtable_equal_mapper (void *key, void *contents, void *arg) { struct hashtable_equal_closure *closure = (struct hashtable_equal_closure *)arg; Lisp_Object keytem, valuetem; + Lisp_Object value_in_other; - /* It would be beautiful if maphash() allowed us to bail out when C - function returns non-zero, a la map_extents() et al. #### Make - it so! */ - if (closure->equal_so_far) + CVOID_TO_LISP (keytem, key); + CVOID_TO_LISP (valuetem, contents); + /* Look up the key in the other hashtable, and compare the values. */ + value_in_other = Fgethash (keytem, closure->other_table, Qunbound); + if (UNBOUNDP (value_in_other) + || !internal_equal (valuetem, value_in_other, closure->depth)) { - Lisp_Object value_in_other; - CVOID_TO_LISP (keytem, key); - CVOID_TO_LISP (valuetem, contents); - /* Look up the key in the other hashtable, and compare the - values. */ - value_in_other = Fgethash (keytem, closure->other_table, Qunbound); - if (UNBOUNDP (value_in_other) - || !internal_equal (valuetem, value_in_other, closure->depth)) - closure->equal_so_far = 0; - /* return 1; */ + /* Give up. */ + closure->equal = 0; + return 1; } - /* return 0; */ + return 0; } static int @@ -133,10 +130,71 @@ return 0; closure.depth = depth + 1; - closure.equal_so_far = 1; + closure.equal = 1; closure.other_table = t2; elisp_maphash (hashtable_equal_mapper, t1, &closure); - return closure.equal_so_far; + return closure.equal; +} + +/* Hashtable hash function. This hashes 5 key-value pairs. For EQ + hashtables, keys are used as the hash value themselves, whereas + values are hashed with internal_hash(). For EQUAL hashtables, both + keys and values are hashed properly. EQL tables are handled as + necessary. All of this should make the hash function compatible + with hashtable_equal(). The elements hashed are the first five + mapped over by maphash(). */ + +struct hashtable_hash_closure +{ + struct hashtable *table; + int depth; + unsigned long hash; + int count; +}; + +/* Needed for tests. */ +static int lisp_object_eql_equal (CONST void *x1, CONST void *x2); +static int lisp_object_equal_equal (CONST void *x1, CONST void *x2); + +static int +hashtable_hash_mapper (void *key, void *contents, void *arg) +{ + struct hashtable_hash_closure *closure = + (struct hashtable_hash_closure *)arg; + Lisp_Object valuetem, keytem; + unsigned long keyhash; + + CVOID_TO_LISP (keytem, key); + CVOID_TO_LISP (valuetem, contents); + + if (!closure->table->test_function) + /* For eq, use key itself as hash. */ + keyhash = LISP_HASH (keytem); + else if (closure->table->test_function == lisp_object_eql_equal) + /* The same as eq, unless the key is float. */ + keyhash = (FLOATP (keytem) + ? internal_hash (keytem, closure->depth) : LISP_HASH (keytem)); + else + /* equal: hash the key properly. */ + keyhash = internal_hash (keytem, closure->depth); + + closure->hash = HASH3 (closure->hash, keyhash, + internal_hash (valuetem, closure->depth)); + return (++closure->count > 5) ? 1 : 0; +} + +static unsigned long +hashtable_hash (Lisp_Object obj, int depth) +{ + struct hashtable_hash_closure closure; + + closure.table = XHASHTABLE (obj); + closure.depth = depth + 1; + closure.hash = 0; + closure.count = 0; + + elisp_maphash (hashtable_hash_mapper, obj, &closure); + return closure.hash; } /* Printing hashtables. @@ -157,7 +215,7 @@ #<hashtable size 2/13 data (key1 value1 key2 value2) 0x874d> The data is truncated to four pairs, and the rest is shown with - `...'. The actual printer is non-consing. */ + `...'. This printer does not cons. */ struct print_hashtable_data_closure { @@ -168,7 +226,7 @@ Lisp_Object printcharfun; }; -static void +static int print_hashtable_data_mapper (void *key, void *contents, void *arg) { Lisp_Object keytem, valuetem; @@ -188,6 +246,7 @@ print_internal (valuetem, closure->printcharfun, 1); } ++closure->count; + return 0; } /* Print the data of the hashtable. This maps through a Lisp @@ -205,10 +264,6 @@ printcharfun); } -/* Needed for tests. */ -static int lisp_object_eql_equal (CONST void *x1, CONST void *x2); -static int lisp_object_equal_equal (CONST void *x1, CONST void *x2); - static void print_hashtable (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) { @@ -226,8 +281,10 @@ "you-d-better-not-see-this")); write_c_string (buf, printcharfun); } - /* These checks are way kludgy... */ - if (table->test_function == NULL) + /* These checks have a kludgy look to them, but they are safe. Due + to nature of hashing, you cannot use arbitrary test functions + anyway. */ + if (!table->test_function) write_c_string (" test eq", printcharfun); else if (table->test_function == lisp_object_equal_equal) write_c_string (" test equal", printcharfun); @@ -521,6 +578,8 @@ int lisp_string_equal (CONST void *x1, CONST void *x2) { + /* This is wrong anyway. You can't use strcmp() on Lisp strings, + because they can contain zero characters. */ Lisp_Object str1, str2; CVOID_TO_LISP (str1, x1); CVOID_TO_LISP (str2, x2); @@ -803,7 +862,7 @@ signal_error (Qinvalid_function, list1 (function)); } -static void +static int lisp_maphash_function (CONST void *void_key, void *void_val, void *void_fn) @@ -814,6 +873,7 @@ VOID_TO_LISP (val, void_val); VOID_TO_LISP (fn, void_fn); call2 (fn, key, val); + return 0; } @@ -840,7 +900,9 @@ lisp hashtable. */ void -elisp_maphash (maphash_function function, Lisp_Object hashtable, void *closure) +elisp_maphash (void (*function) (CONST void *key, void *contents, + void *extra_arg), + Lisp_Object hashtable, void *closure) { struct _C_hashtable htbl; @@ -850,7 +912,10 @@ } void -elisp_map_remhash (remhash_predicate function, Lisp_Object hashtable, +elisp_map_remhash (int (*function) (CONST void *key, + CONST void *contents, + void *extra_arg), + Lisp_Object hashtable, void *closure) { struct _C_hashtable htbl; @@ -933,7 +998,7 @@ int did_mark; }; -static void +static int marking_mapper (CONST void *key, void *contents, void *closure) { Lisp_Object keytem, valuetem; @@ -1001,7 +1066,7 @@ abort (); /* Huh? */ } - return; + return 0; } int @@ -1189,6 +1254,19 @@ return LISP_HASH (obj); } +#if 0 +xxDEFUN ("internal-hash-value", Finternal_hash_value, 1, 1, 0, /* +Hash value of OBJECT. For debugging. +The value is returned as (HIGH . LOW). +*/ + (object)) +{ + /* This function is pretty 32bit-centric. */ + unsigned long hash = internal_hash (object, 0); + return Fcons (hash >> 16, hash & 0xffff); +} +#endif + /************************************************************************/ /* initialization */ @@ -1209,6 +1287,9 @@ DEFSUBR (Fmake_weak_hashtable); DEFSUBR (Fmake_key_weak_hashtable); DEFSUBR (Fmake_value_weak_hashtable); +#if 0 + DEFSUBR (Finternal_hash_value); +#endif defsymbol (&Qhashtablep, "hashtablep"); defsymbol (&Qhashtable, "hashtable"); defsymbol (&Qweak, "weak");