aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2019-07-22 21:27:33 -0700
committerPaul Eggert2019-07-22 21:28:18 -0700
commitf378ed1a0b1ca2ceed5afabcf5f303ae339039ba (patch)
tree767e994477690e2681cb7fe027af7d708efd6cc6
parent97477edaf2044e51696f46b166b43801893156a3 (diff)
downloademacs-f378ed1a0b1ca2ceed5afabcf5f303ae339039ba.tar.gz
emacs-f378ed1a0b1ca2ceed5afabcf5f303ae339039ba.zip
Avoid overexposing fixnums for hash codes
Following a suggestion by Stefan Monnier in: https://lists.gnu.org/r/emacs-devel/2019-07/msg00530.html * doc/lispref/hash.texi (Creating Hash, Defining Hash): * src/fns.c (Fsxhash_eq, Fsxhash_eql, Fsxhash_equal, Fmake_hash_table): Don’t insist that hash codes be fixnums, reverting the recent doc changes to the contrary. * src/bytecode.c (exec_byte_code): Special-case only the eq case, as the others aren’t worth tuning now that we treat bignum hashes like fixnums. * src/fns.c (hashfn_user_defined): If the hash code is a bignum, reduce its hash down to a fixnum.
-rw-r--r--doc/lispref/hash.texi16
-rw-r--r--src/bytecode.c14
-rw-r--r--src/fns.c12
3 files changed, 19 insertions, 23 deletions
diff --git a/doc/lispref/hash.texi b/doc/lispref/hash.texi
index 051531491c0..50d4c5742cb 100644
--- a/doc/lispref/hash.texi
+++ b/doc/lispref/hash.texi
@@ -132,7 +132,7 @@ When you add an association to a hash table and the table is full,
132it grows automatically. This value specifies how to make the hash table 132it grows automatically. This value specifies how to make the hash table
133larger, at that time. 133larger, at that time.
134 134
135If @var{rehash-size} is a fixnum, it should be positive and the hash 135If @var{rehash-size} is an integer, it should be positive, and the hash
136table grows by adding approximately that much to the nominal size. If 136table grows by adding approximately that much to the nominal size. If
137@var{rehash-size} is floating point, it had better be greater 137@var{rehash-size} is floating point, it had better be greater
138than 1, and the hash table grows by multiplying the old size by 138than 1, and the hash table grows by multiplying the old size by
@@ -239,8 +239,8 @@ to understand how hash tables work, and what a @dfn{hash code} means.
239 239
240 You can think of a hash table conceptually as a large array of many 240 You can think of a hash table conceptually as a large array of many
241slots, each capable of holding one association. To look up a key, 241slots, each capable of holding one association. To look up a key,
242@code{gethash} first computes a fixnum, the hash code, from the key. 242@code{gethash} first computes an integer, the hash code, from the key.
243It reduces this fixnum modulo the length of the array, to produce an 243It can reduce this integer modulo the length of the array, to produce an
244index in the array. Then it looks in that slot, and if necessary in 244index in the array. Then it looks in that slot, and if necessary in
245other nearby slots, to see if it has found the key being sought. 245other nearby slots, to see if it has found the key being sought.
246 246
@@ -265,7 +265,7 @@ The function @var{test-fn} should accept two arguments, two keys, and
265return non-@code{nil} if they are considered the same. 265return non-@code{nil} if they are considered the same.
266 266
267The function @var{hash-fn} should accept one argument, a key, and return 267The function @var{hash-fn} should accept one argument, a key, and return
268a fixnum that is the hash code of that key. For good results, the 268an integer that is the hash code of that key. For good results, the
269function should use the whole range of fixnums for hash codes, 269function should use the whole range of fixnums for hash codes,
270including negative fixnums. 270including negative fixnums.
271 271
@@ -276,12 +276,12 @@ under the property @code{hash-table-test}; the property value's form is
276 276
277@defun sxhash-equal obj 277@defun sxhash-equal obj
278This function returns a hash code for Lisp object @var{obj}. 278This function returns a hash code for Lisp object @var{obj}.
279This is a fixnum that reflects the contents of @var{obj} 279This is an integer that reflects the contents of @var{obj}
280and the other Lisp objects it points to. 280and the other Lisp objects it points to.
281 281
282If two objects @var{obj1} and @var{obj2} are @code{equal}, then 282If two objects @var{obj1} and @var{obj2} are @code{equal}, then
283@code{(sxhash-equal @var{obj1})} and @code{(sxhash-equal @var{obj2})} 283@code{(sxhash-equal @var{obj1})} and @code{(sxhash-equal @var{obj2})}
284are the same fixnum. 284are the same integer.
285 285
286If the two objects are not @code{equal}, the values returned by 286If the two objects are not @code{equal}, the values returned by
287@code{sxhash-equal} are usually different, but not always; once in a 287@code{sxhash-equal} are usually different, but not always; once in a
@@ -299,7 +299,7 @@ result reflects identity of @var{obj}, but not its contents.
299 299
300If two objects @var{obj1} and @var{obj2} are @code{eq}, then 300If two objects @var{obj1} and @var{obj2} are @code{eq}, then
301@code{(sxhash-eq @var{obj1})} and @code{(sxhash-eq @var{obj2})} are 301@code{(sxhash-eq @var{obj1})} and @code{(sxhash-eq @var{obj2})} are
302the same fixnum. 302the same integer.
303@end defun 303@end defun
304 304
305@defun sxhash-eql obj 305@defun sxhash-eql obj
@@ -310,7 +310,7 @@ in which case a hash code is generated for the value.
310 310
311If two objects @var{obj1} and @var{obj2} are @code{eql}, then 311If two objects @var{obj1} and @var{obj2} are @code{eql}, then
312@code{(sxhash-eql @var{obj1})} and @code{(sxhash-eql @var{obj2})} are 312@code{(sxhash-eql @var{obj1})} and @code{(sxhash-eql @var{obj2})} are
313the same fixnum. 313the same integer.
314@end defun 314@end defun
315 315
316 This example creates a hash table whose keys are strings that are 316 This example creates a hash table whose keys are strings that are
diff --git a/src/bytecode.c b/src/bytecode.c
index d668a9a6a15..9aad1eb642b 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -1406,18 +1406,12 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
1406 1406
1407 /* h->count is a faster approximation for HASH_TABLE_SIZE (h) 1407 /* h->count is a faster approximation for HASH_TABLE_SIZE (h)
1408 here. */ 1408 here. */
1409 if (h->count <= 5) 1409 if (h->count <= 5 && !h->test.cmpfn)
1410 { /* Do a linear search if there are not many cases 1410 { /* Do a linear search if there are not many cases
1411 FIXME: 5 is arbitrarily chosen. */ 1411 FIXME: 5 is arbitrarily chosen. */
1412 Lisp_Object hash_code 1412 for (i = h->count; 0 <= --i; )
1413 = h->test.cmpfn ? h->test.hashfn (v1, h) : Qnil; 1413 if (EQ (v1, HASH_KEY (h, i)))
1414 1414 break;
1415 for (i = h->count; 0 <= --i; )
1416 if (EQ (v1, HASH_KEY (h, i))
1417 || (h->test.cmpfn
1418 && EQ (hash_code, HASH_HASH (h, i))
1419 && !NILP (h->test.cmpfn (v1, HASH_KEY (h, i), h))))
1420 break;
1421 } 1415 }
1422 else 1416 else
1423 i = hash_lookup (h, v1, NULL); 1417 i = hash_lookup (h, v1, NULL);
diff --git a/src/fns.c b/src/fns.c
index 734a2e253c7..d28d437df9c 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -47,6 +47,7 @@ static void sort_vector_copy (Lisp_Object, ptrdiff_t,
47enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES }; 47enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES };
48static bool internal_equal (Lisp_Object, Lisp_Object, 48static bool internal_equal (Lisp_Object, Lisp_Object,
49 enum equal_kind, int, Lisp_Object); 49 enum equal_kind, int, Lisp_Object);
50static EMACS_UINT sxhash_bignum (struct Lisp_Bignum *);
50 51
51DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, 52DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
52 doc: /* Return the argument unchanged. */ 53 doc: /* Return the argument unchanged. */
@@ -4021,7 +4022,8 @@ Lisp_Object
4021hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) 4022hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h)
4022{ 4023{
4023 Lisp_Object args[] = { h->test.user_hash_function, key }; 4024 Lisp_Object args[] = { h->test.user_hash_function, key };
4024 return hash_table_user_defined_call (ARRAYELTS (args), args, h); 4025 Lisp_Object hash = hash_table_user_defined_call (ARRAYELTS (args), args, h);
4026 return BIGNUMP (hash) ? make_fixnum (sxhash_bignum (XBIGNUM (hash))) : hash;
4025} 4027}
4026 4028
4027struct hash_table_test const 4029struct hash_table_test const
@@ -4707,7 +4709,7 @@ sxhash (Lisp_Object obj, int depth)
4707 ***********************************************************************/ 4709 ***********************************************************************/
4708 4710
4709DEFUN ("sxhash-eq", Fsxhash_eq, Ssxhash_eq, 1, 1, 0, 4711DEFUN ("sxhash-eq", Fsxhash_eq, Ssxhash_eq, 1, 1, 0,
4710 doc: /* Return a fixnum hash code for OBJ suitable for `eq'. 4712 doc: /* Return an integer hash code for OBJ suitable for `eq'.
4711If (eq A B), then (= (sxhash-eq A) (sxhash-eq B)). 4713If (eq A B), then (= (sxhash-eq A) (sxhash-eq B)).
4712 4714
4713Hash codes are not guaranteed to be preserved across Emacs sessions. */) 4715Hash codes are not guaranteed to be preserved across Emacs sessions. */)
@@ -4717,7 +4719,7 @@ Hash codes are not guaranteed to be preserved across Emacs sessions. */)
4717} 4719}
4718 4720
4719DEFUN ("sxhash-eql", Fsxhash_eql, Ssxhash_eql, 1, 1, 0, 4721DEFUN ("sxhash-eql", Fsxhash_eql, Ssxhash_eql, 1, 1, 0,
4720 doc: /* Return a fixnum hash code for OBJ suitable for `eql'. 4722 doc: /* Return an integer hash code for OBJ suitable for `eql'.
4721If (eql A B), then (= (sxhash-eql A) (sxhash-eql B)). 4723If (eql A B), then (= (sxhash-eql A) (sxhash-eql B)).
4722 4724
4723Hash codes are not guaranteed to be preserved across Emacs sessions. */) 4725Hash codes are not guaranteed to be preserved across Emacs sessions. */)
@@ -4727,7 +4729,7 @@ Hash codes are not guaranteed to be preserved across Emacs sessions. */)
4727} 4729}
4728 4730
4729DEFUN ("sxhash-equal", Fsxhash_equal, Ssxhash_equal, 1, 1, 0, 4731DEFUN ("sxhash-equal", Fsxhash_equal, Ssxhash_equal, 1, 1, 0,
4730 doc: /* Return a fixnum hash code for OBJ suitable for `equal'. 4732 doc: /* Return an integer hash code for OBJ suitable for `equal'.
4731If (equal A B), then (= (sxhash-equal A) (sxhash-equal B)). 4733If (equal A B), then (= (sxhash-equal A) (sxhash-equal B)).
4732 4734
4733Hash codes are not guaranteed to be preserved across Emacs sessions. */) 4735Hash codes are not guaranteed to be preserved across Emacs sessions. */)
@@ -4751,7 +4753,7 @@ keys. Default is `eql'. Predefined are the tests `eq', `eql', and
4751Default is 65. 4753Default is 65.
4752 4754
4753:rehash-size REHASH-SIZE - Indicates how to expand the table when it 4755:rehash-size REHASH-SIZE - Indicates how to expand the table when it
4754fills up. If REHASH-SIZE is a fixnum, increase the size by that 4756fills up. If REHASH-SIZE is an integer, increase the size by that
4755amount. If it is a float, it must be > 1.0, and the new size is the 4757amount. If it is a float, it must be > 1.0, and the new size is the
4756old size multiplied by that factor. Default is 1.5. 4758old size multiplied by that factor. Default is 1.5.
4757 4759