]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix hash functions for bignums
authorTom Tromey <tom@tromey.com>
Sat, 4 Aug 2018 17:08:31 +0000 (11:08 -0600)
committerTom Tromey <tom@tromey.com>
Sat, 4 Aug 2018 17:08:31 +0000 (11:08 -0600)
* 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
test/src/fns-tests.el

index b14481d0101c87e6d29086b73c74f5f20f1db38d..ac93a2f6d81b1dbfe7afce07957af238c4b3ad23 100644 (file)
--- 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;
index d440cfabda4986ceb351c36211418a8ddd8a3fc7..d560f0bb0d974d66d2f81497e1513c73f8a30222 100644 (file)
     (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)