From 0426bd2fae19ae0492d44407f17ac1005196c9c3 Mon Sep 17 00:00:00 2001
From: Attila Lendvai <attila@lendvai.name>
Date: Mon, 10 Apr 2017 18:15:37 +0200
Subject: [PATCH] Fix: earlier keys take priority in ALIST-HASH-TABLE and
 PLIST-HASH-TABLE

Also record tests for the new behavior.

This is a semantic change, but more in line with how alists and
plists are defined in the CLHS.

See '15.6. Association Lists' and 'property list' in the Glossary.

Reported by Christoph Arenz to alexandria-devel in
'Wrong handling of duplicate keys in alist-hash-table and plist-hash-table'.
---
 hash-tables.lisp |  4 ++--
 tests.lisp       | 18 ++++++++++++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/hash-tables.lisp b/hash-tables.lisp
index f461a70..a9f7902 100644
--- a/hash-tables.lisp
+++ b/hash-tables.lisp
@@ -88,7 +88,7 @@ TABLE."
 ALIST. Hash table is initialized using the HASH-TABLE-INITARGS."
   (let ((table (apply #'make-hash-table hash-table-initargs)))
     (dolist (cons alist)
-      (setf (gethash (car cons) table) (cdr cons)))
+      (ensure-gethash (car cons) table (cdr cons)))
     table))
 
 (defun plist-hash-table (plist &rest hash-table-initargs)
@@ -97,5 +97,5 @@ PLIST. Hash table is initialized using the HASH-TABLE-INITARGS."
   (let ((table (apply #'make-hash-table hash-table-initargs)))
     (do ((tail plist (cddr tail)))
         ((not tail))
-      (setf (gethash (car tail) table) (cadr tail)))
+      (ensure-gethash (car tail) table (cadr tail)))
     table))
diff --git a/tests.lisp b/tests.lisp
index a00a700..b70ef04 100644
--- a/tests.lisp
+++ b/tests.lisp
@@ -373,6 +373,15 @@
                 (hash-table-test table))))
   (3 (a) (b) (c) t))
 
+(deftest alist-hash-table.duplicate-keys
+    (let* ((alist '((0 a) (1 b) (0 c) (1 d) (2 e)))
+           (table (alist-hash-table alist)))
+      (list (hash-table-count table)
+            (gethash 0 table)
+            (gethash 1 table)
+            (gethash 2 table)))
+  (3 (a) (b) (e)))
+
 (deftest plist-hash-table.1
     (let* ((plist '(:a 1 :b 2 :c 3))
            (table (plist-hash-table plist :test 'eq)))
@@ -386,6 +395,15 @@
                 (hash-table-test table))))
   (3 1 2 3 nil nil t))
 
+(deftest plist-hash-table.duplicate-keys
+    (let* ((plist '(:a 1 :b 2 :a 3 :b 4 :c 5))
+           (table (plist-hash-table plist)))
+      (list (hash-table-count table)
+            (gethash :a table)
+            (gethash :b table)
+            (gethash :c table)))
+  (3 1 2 5))
+
 ;;;; Functions
 
 (deftest disjoin.1
-- 
GitLab