From 1303f8a4806fb170c14375c53b0f79d03e288eb3 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Sat, 4 Aug 2018 11:08:31 -0600 Subject: [PATCH] Fix hash functions for bignums * src/fns.c (cmpfn_eql, hashfn_eql): Handle bignums. (sxhash_bignum): New function. (sxhash): Use it. * test/src/fns-tests.el (test-bignum-hash): New test. --- src/fns.c | 34 ++++++++++++++++++++++++++++++---- test/src/fns-tests.el | 11 +++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/fns.c b/src/fns.c index b14481d0101..ac93a2f6d81 100644 --- a/src/fns.c +++ b/src/fns.c @@ -3717,9 +3717,13 @@ cmpfn_eql (struct hash_table_test *ht, Lisp_Object key1, Lisp_Object key2) { - return (FLOATP (key1) - && FLOATP (key2) - && XFLOAT_DATA (key1) == XFLOAT_DATA (key2)); + if (FLOATP (key1) + && FLOATP (key2) + && XFLOAT_DATA (key1) == XFLOAT_DATA (key2)) + return true; + return (BIGNUMP (key1) + && BIGNUMP (key2) + && mpz_cmp (XBIGNUM (key1)->value, XBIGNUM (key2)->value) == 0); } @@ -3775,7 +3779,9 @@ hashfn_equal (struct hash_table_test *ht, Lisp_Object key) static EMACS_UINT hashfn_eql (struct hash_table_test *ht, Lisp_Object key) { - return FLOATP (key) ? hashfn_equal (ht, key) : hashfn_eq (ht, key); + return ((FLOATP (key) || BIGNUMP (key)) + ? hashfn_equal (ht, key) + : hashfn_eq (ht, key)); } /* Value is a hash code for KEY for use in hash table H which uses as @@ -4409,6 +4415,20 @@ sxhash_bool_vector (Lisp_Object vec) return SXHASH_REDUCE (hash); } +/* Return a hash for a bignum. */ + +static EMACS_UINT +sxhash_bignum (struct Lisp_Bignum *bignum) +{ + size_t i, nlimbs = mpz_size (bignum->value); + EMACS_UINT hash = 0; + + for (i = 0; i < nlimbs; ++i) + hash = sxhash_combine (hash, mpz_getlimbn (bignum->value, i)); + + return SXHASH_REDUCE (hash); +} + /* Return a hash code for OBJ. DEPTH is the current depth in the Lisp structure. Value is an unsigned integer clipped to INTMASK. */ @@ -4428,6 +4448,12 @@ sxhash (Lisp_Object obj, int depth) break; case Lisp_Misc: + if (XMISCTYPE (obj) == Lisp_Misc_Bignum) + { + hash = sxhash_bignum (XBIGNUM (obj)); + break; + } + FALLTHROUGH; case Lisp_Symbol: hash = XHASH (obj); break; diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el index d440cfabda4..d560f0bb0d9 100644 --- a/test/src/fns-tests.el +++ b/test/src/fns-tests.el @@ -602,4 +602,15 @@ (should (equal x y)) (should-not (eql x 0.0e+NaN)))) +(ert-deftest test-bignum-hash () + "Test that hash tables work for bignums." + ;; Make two bignums that are eql but not eq. + (let ((b1 (1+ most-positive-fixnum)) + (b2 (1+ most-positive-fixnum))) + (dolist (test '(eq eql equal)) + (let ((hash (make-hash-table :test test))) + (puthash b1 t hash) + (should (eq (gethash b2 hash) + (funcall test b1 b2))))))) + (provide 'fns-tests) -- 2.39.2