]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/map.el
Fix a false negative in `map-elt' with alists and values being nil
[gnu-emacs] / lisp / emacs-lisp / map.el
index fec06343f7ca0d43153f5996064b4862ba48fb0e..ebf1fe9589abccf7ac7719b4de67301c56c06a92 100644 (file)
   "Perform a lookup in MAP of KEY and return its associated value.
 If KEY is not found, return DEFAULT which defaults to nil.
 
-If MAP is a list, `assoc' is used to lookup KEY."
+If MAP is a list, `equal' is used to lookup KEY."
   (map--dispatch map
-    :list (or (cdr (assoc key map)) default)
+    :list (map--elt-list map key default)
     :hash-table (gethash key map default)
-    :array (or (ignore-errors (elt map key)) default)))
+    :array (map--elt-array map key default)))
 
 (defmacro map-put (map key value)
   "In MAP, associate KEY with VALUE and return MAP.
-If KEY is already present in MAP, replace its value with VALUE."
+If KEY is already present in MAP, replace the associated value
+with VALUE."
   (declare (debug t))
   `(progn
      (map--dispatch (m ,map m)
@@ -72,7 +73,7 @@ If MAP is an array, store nil at the index KEY."
      (map--dispatch (m ,map m)
        :list (setq ,map (map--delete-alist m ,key))
        :hash-table (remhash ,key m)
-       :array (aset m ,key nil))))
+       :array (map--delete-array m ,key))))
 
 (defun map-nested-elt (map keys &optional default)
   "Travserse MAP using KEYS and return the looked up value or DEFAULT if nil.
@@ -86,11 +87,11 @@ Map can be a nested map composed of alists, hash-tables and arrays."
 
 (defun map-keys (map)
   "Return the list of keys in MAP."
-  (map-apply (lambda (key value) key) map))
+  (map-apply (lambda (key _) key) map))
 
 (defun map-values (map)
   "Return the list of values in MAP."
-  (map-apply (lambda (key value) value) map))
+  (map-apply (lambda (_ value) value) map))
 
 (defun map-pairs (map)
   "Return the elements of MAP as key/value association lists."
@@ -121,13 +122,13 @@ FUNCTION is called with two arguments, the key and the value."
 
 (defun map-keys-apply (function map)
   "Return the result of applying FUNCTION to each key of MAP."
-  (map-apply (lambda (key val)
+  (map-apply (lambda (key _)
                (funcall function key))
              map))
 
 (defun map-values-apply (function map)
   "Return the result of applying FUNCTION to each value of MAP."
-  (map-apply (lambda (key val)
+  (map-apply (lambda (_ val)
                (funcall function val))
              map))
 
@@ -193,7 +194,8 @@ MAP can be a list, hash-table or array."
 TYPE can be one of the following symbols: list or hash-table."
   (pcase type
     (`list (map-pairs map))
-    (`hash-table (map--into-hash-table map))))
+    (`hash-table (map--into-hash-table map))
+    (t (error "Not a map type name: %S" type))))
 
 (defmacro map--dispatch (spec &rest args)
   "Evaluate one of the provided forms depending on the type of MAP.
@@ -204,7 +206,7 @@ ARGS should have the form [TYPE FORM]...
 The following keyword types are meaningful: `:list',
 `:hash-table' and `array'.
 
-An error is thrown if MAP is neither a list, hash-table or array.
+An error is thrown if MAP is neither a list, hash-table nor array.
 
 Return RESULT if non-nil or the result of evaluation of the
 form.
@@ -251,12 +253,37 @@ form.
                   (setq index (1+ index))))
               map)))
 
+(defun map--elt-list (map key &optional default)
+  "Return the element of the list MAP at the index KEY.
+If KEY is not found, return DEFAULT which defaults to nil."
+  (let ((pair (assoc key map)))
+    (if pair
+        (cdr (assoc key map))
+      default)))
+
+(defun map--elt-array (map key &optional default)
+  "Return the element of the array MAP at the index KEY.
+If KEY is not found, return DEFAULT which defaults to nil."
+  (let ((len (seq-length map)))
+    (or (and (>= key 0)
+             (<= key len)
+             (seq-elt map key))
+        default)))
+
 (defun map--delete-alist (map key)
   "Return MAP with KEY removed."
   (seq-remove (lambda (pair)
                 (equal key (car pair)))
               map))
 
+(defun map--delete-array (map key)
+  "Set nil in the array MAP at the index KEY if present and return MAP."
+  (let ((len (seq-length map)))
+    (and (>= key 0)
+         (<= key len)
+         (aset m key nil)))
+  map)
+
 (defun map--into-hash-table (map)
   "Convert MAP into a hash-table."
   (let ((ht (make-hash-table :size (map-length map)