summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/fns.c34
-rw-r--r--test/src/fns-tests.el11
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)