diff --git a/lists.lisp b/lists.lisp index 00b42fafdbaf0ca11af11640507fea270780ff4c..feaa72633607e0e43a947cd190734b0096c29d45 100644 --- a/lists.lisp +++ b/lists.lisp @@ -278,8 +278,20 @@ not destructively modified. Keys are compared using EQ." (defun delete-from-plist (plist &rest keys) "Just like REMOVE-FROM-PLIST, but this version may destructively modify the provided plist." - ;; FIXME: should not cons - (apply 'remove-from-plist plist keys)) + (declare (optimize speed)) + (loop with head = plist + with tail = nil ; a nil tail means an empty result so far + for (key . rest) on plist by #'cddr + do (assert rest () "Expected a proper plist, got ~S" plist) + (if (member key keys :test #'eq) + ;; skip over this pair + (symbol-macrolet ((next (cdr rest))) + (if tail + (setf (cdr tail) next) + (setf head next))) + ;; keep this pair + (setf tail rest)) + finally (return head))) (define-modify-macro remove-from-plistf (&rest keys) remove-from-plist "Modify macro for REMOVE-FROM-PLIST.")