From: Pip Cet <pipcet@gmail.com>
Date: Sun, 20 Sep 2020 10:24:16 +0000 (+0200)
Subject: Fix printing of hash tables with removed elements
X-Git-Tag: emacs-28.0.90~5990
X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=988f45a75b745dc1fee6315749ddb48f00b000eb;p=emacs.git

Fix printing of hash tables with removed elements

* src/print.c (print_vectorlike): Keep track of the actual number
of elements printed rather than attempting to use hash bucket
indices (bug#38892).
---

diff --git a/src/print.c b/src/print.c
index bd1769144e0..0ecc98f37bf 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1590,27 +1590,34 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
 
 	/* Print the data here as a plist. */
 	ptrdiff_t real_size = HASH_TABLE_SIZE (h);
-	ptrdiff_t size = real_size;
+	ptrdiff_t size = h->count;
 
 	/* Don't print more elements than the specified maximum.  */
 	if (FIXNATP (Vprint_length) && XFIXNAT (Vprint_length) < size)
 	  size = XFIXNAT (Vprint_length);
 
 	printchar ('(', printcharfun);
-	for (ptrdiff_t i = 0; i < size; i++)
+	ptrdiff_t j = 0;
+	for (ptrdiff_t i = 0; i < real_size; i++)
           {
             Lisp_Object key = HASH_KEY (h, i);
 	    if (!EQ (key, Qunbound))
 	      {
-	        if (i) printchar (' ', printcharfun);
+	        if (j++) printchar (' ', printcharfun);
 	        print_object (key, printcharfun, escapeflag);
 	        printchar (' ', printcharfun);
 	        print_object (HASH_VALUE (h, i), printcharfun, escapeflag);
+		if (j == size)
+		  break;
 	      }
           }
 
-	if (size < real_size)
-	  print_c_string (" ...", printcharfun);
+	if (j < h->count)
+	  {
+	    if (j)
+	      printchar (' ', printcharfun);
+	    print_c_string ("...", printcharfun);
+	  }
 
 	print_c_string ("))", printcharfun);
       }
diff --git a/test/src/print-tests.el b/test/src/print-tests.el
index 42e5962137c..51ef16dd85a 100644
--- a/test/src/print-tests.el
+++ b/test/src/print-tests.el
@@ -355,5 +355,33 @@ otherwise, use a different charset."
     (setcdr err err)
     (should-error (error-message-string err) :type 'circular-list)))
 
+(print-tests--deftest print-hash-table-test ()
+  (should
+   (string-match
+    "data (2 3)"
+    (let ((h (make-hash-table)))
+      (puthash 1 2 h)
+      (puthash 2 3 h)
+      (remhash 1 h)
+      (format "%S" h))))
+
+  (should
+   (string-match
+    "data ()"
+    (let ((h (make-hash-table)))
+      (let ((print-length 0))
+        (format "%S" h)))))
+
+  (should
+   (string-match
+    "data (99 99"
+    (let ((h (make-hash-table)))
+      (dotimes (i 100)
+        (puthash i i h))
+      (dotimes (i 99)
+        (remhash i h))
+      (let ((print-length 1))
+        (format "%S" h))))))
+
 (provide 'print-tests)
 ;;; print-tests.el ends here