aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Petton2015-06-21 20:46:08 +0200
committerNicolas Petton2015-06-21 20:49:16 +0200
commit8b6d82d3ca86f76ed964063b3941a7c6ab0bf1c6 (patch)
tree9ec9c3d28fa320bcaa3c2e177939cba0b5006ec2
parent8d4f1e3bd742278d6a3d4c42811845b860d0d104 (diff)
downloademacs-8b6d82d3ca86f76ed964063b3941a7c6ab0bf1c6.tar.gz
emacs-8b6d82d3ca86f76ed964063b3941a7c6ab0bf1c6.zip
Define `map-elt' as a generalized variable
* lisp/emacs-lisp/map.el (map-elt): Define a gv-expander. * lisp/emacs-lisp/map.el (map--dispatch): Tighten the code. * lisp/emacs-lisp/map.el (map-put): Redefine it as a function using a `setf' with `map-elt'. * test/automated/map-tests.el: Comment out `test-map-put-literal'.
-rw-r--r--lisp/emacs-lisp/map.el52
-rw-r--r--test/automated/map-tests.el24
2 files changed, 40 insertions, 36 deletions
diff --git a/lisp/emacs-lisp/map.el b/lisp/emacs-lisp/map.el
index 1d8a3126bba..8759616053a 100644
--- a/lisp/emacs-lisp/map.el
+++ b/lisp/emacs-lisp/map.el
@@ -82,25 +82,21 @@ The following keyword types are meaningful: `:list',
82 82
83An error is thrown if MAP is neither a list, hash-table nor array. 83An error is thrown if MAP is neither a list, hash-table nor array.
84 84
85Return RESULT if non-nil or the result of evaluation of the 85Return RESULT if non-nil or the result of evaluation of the form.
86form.
87 86
88\(fn (VAR MAP [RESULT]) &rest ARGS)" 87\(fn (VAR MAP [RESULT]) &rest ARGS)"
89 (declare (debug t) (indent 1)) 88 (declare (debug t) (indent 1))
90 (unless (listp spec) 89 (unless (listp spec)
91 (setq spec `(,spec ,spec))) 90 (setq spec `(,spec ,spec)))
92 (let ((map-var (car spec)) 91 (let ((map-var (car spec)))
93 (result-var (make-symbol "result"))) 92 `(let* ,(unless (eq map-var (cadr spec)) `((,map-var ,(cadr spec))))
94 `(let ((,map-var ,(cadr spec)) 93 (cond ((listp ,map-var) ,(plist-get args :list))
95 ,result-var) 94 ((hash-table-p ,map-var) ,(plist-get args :hash-table))
96 (setq ,result-var 95 ((arrayp ,map-var) ,(plist-get args :array))
97 (cond ((listp ,map-var) ,(plist-get args :list)) 96 (t (error "Unsupported map: %s" ,map-var)))
98 ((hash-table-p ,map-var) ,(plist-get args :hash-table)) 97 ,@(cddr spec))))
99 ((arrayp ,map-var) ,(plist-get args :array)) 98
100 (t (error "Unsupported map: %s" ,map-var)))) 99(put 'map--raw-place 'gv-expander #'funcall)
101 ,@(when (cddr spec)
102 `((setq ,result-var ,@(cddr spec))))
103 ,result-var)))
104 100
105(defun map-elt (map key &optional default) 101(defun map-elt (map key &optional default)
106 "Perform a lookup in MAP of KEY and return its associated value. 102 "Perform a lookup in MAP of KEY and return its associated value.
@@ -109,26 +105,34 @@ If KEY is not found, return DEFAULT which defaults to nil.
109If MAP is a list, `eql' is used to lookup KEY. 105If MAP is a list, `eql' is used to lookup KEY.
110 106
111MAP can be a list, hash-table or array." 107MAP can be a list, hash-table or array."
108 (declare
109 (gv-expander
110 (lambda (do)
111 (gv-letplace (mgetter msetter) map
112 (macroexp-let2* nil
113 ;; Eval them once and for all in the right order.
114 ((key key) (default default))
115 `(map--dispatch ,mgetter
116 :list ,(gv-get `(alist-get ,key (map--raw-place ,mgetter ,msetter)
117 ,default)
118 do)
119 :hash-table ,(gv-get `(gethash ,key (map--raw-place ,mgetter ,msetter)
120 ,default))
121 :array ,(gv-get (aref (map--raw-place ,mgetter ,msetter) ,key)
122 do)))))))
112 (map--dispatch map 123 (map--dispatch map
113 :list (alist-get key map default) 124 :list (alist-get key map default)
114 :hash-table (gethash key map default) 125 :hash-table (gethash key map default)
115 :array (map--elt-array map key default))) 126 :array (map--elt-array map key default)))
116 127
117(defmacro map-put (map key value) 128(defun map-put (map key value)
118 "In MAP, associate KEY with VALUE and return MAP. 129 "In MAP, associate KEY with VALUE and return MAP.
119If KEY is already present in MAP, replace the associated value 130If KEY is already present in MAP, replace the associated value
120with VALUE. 131with VALUE.
121 132
122MAP can be a list, hash-table or array." 133MAP can be a list, hash-table or array."
123 (declare (debug t)) 134 (setf (map-elt map key) value)
124 (let ((symbol (symbolp map))) 135 map)
125 `(progn
126 (map--dispatch (m ,map m)
127 :list (if ,symbol
128 (setq ,map (cons (cons ,key ,value) m))
129 (error "Literal lists are not allowed, %s must be a symbol" ',map))
130 :hash-table (puthash ,key ,value m)
131 :array (aset m ,key ,value)))))
132 136
133(defmacro map-delete (map key) 137(defmacro map-delete (map key)
134 "In MAP, delete the key KEY if present and return MAP. 138 "In MAP, delete the key KEY if present and return MAP.
diff --git a/test/automated/map-tests.el b/test/automated/map-tests.el
index abda03d9d04..402fead88f7 100644
--- a/test/automated/map-tests.el
+++ b/test/automated/map-tests.el
@@ -40,11 +40,11 @@ Evaluate BODY for each created map.
40 (let ((alist (make-symbol "alist")) 40 (let ((alist (make-symbol "alist"))
41 (vec (make-symbol "vec")) 41 (vec (make-symbol "vec"))
42 (ht (make-symbol "ht"))) 42 (ht (make-symbol "ht")))
43 `(let ((,alist '((0 . 3) 43 `(let ((,alist (list (cons 0 3)
44 (1 . 4) 44 (cons 1 4)
45 (2 . 5))) 45 (cons 2 5)))
46 (,vec (make-vector 3 nil)) 46 (,vec (make-vector 3 nil))
47 (,ht (make-hash-table))) 47 (,ht (make-hash-table)))
48 (aset ,vec 0 '3) 48 (aset ,vec 0 '3)
49 (aset ,vec 1 '4) 49 (aset ,vec 1 '4)
50 (aset ,vec 2 '5) 50 (aset ,vec 2 '5)
@@ -87,13 +87,13 @@ Evaluate BODY for each created map.
87 (let ((vec [3 4 5])) 87 (let ((vec [3 4 5]))
88 (should-error (map-put vec 3 6)))) 88 (should-error (map-put vec 3 6))))
89 89
90(ert-deftest test-map-put-literal () 90;; (ert-deftest test-map-put-literal ()
91 (should (= (map-elt (map-put [1 2 3] 1 4) 1) 91;; (should (= (map-elt (map-put [1 2 3] 1 4) 1)
92 4)) 92;; 4))
93 (should (= (map-elt (map-put (make-hash-table) 'a 2) 'a) 93;; (should (= (map-elt (map-put (make-hash-table) 'a 2) 'a)
94 2)) 94;; 2))
95 (should-error (map-put '((a . 1)) 'b 2)) 95;; (should-error (map-put '((a . 1)) 'b 2))
96 (should-error (map-put '() 'a 1))) 96;; (should-error (map-put '() 'a 1)))
97 97
98(ert-deftest test-map-put-return-value () 98(ert-deftest test-map-put-return-value ()
99 (let ((ht (make-hash-table))) 99 (let ((ht (make-hash-table)))