Attached is a proper patch.
-Robert
On Sat, Feb 23, 2013 at 1:09 AM, Robert Smith quad@symbo1ics.com wrote:
Hey:
Here's a destructive/non-consing version of DELETE-FROM-PLIST. I've tested with (I think) all corner cases from the REPL, but I ought to write tests proper.
The function is here http://tinyurl.com/adqkssu ;or the following huge link, in case the last one is invalidated https://bitbucket.org/tarballs_are_good/lisp-random/src/3db634111d35e788c6ea... .
For simplicity or ease of review from an email client, I've pasted the function at the end of this email.
Additionally, this function would make it pretty easy to write DELETE-FROM-PLIST-IF{-NOT}, since the function to determine if a key is bad is factored out. If one did write this function, then it would be easy to define DELETE-FROM-PLIST in terms of it.
Let me know if there are any changes that should be made.
Cheers,
Robert Smith
;;;; from delete-from-plist.lisp
(defun delete-from-plist (plist &rest keys) "Delete all keys and pairs indicated by KEYS from the plist PLIST." (labels ((assert-proper-plist (x) (assert x () "Expected a proper plist, got ~S" plist)) (bad-key-p (key) (member key keys :test #'eq)) (find-first () "Find the first cons in PLIST to keep." (loop :for the-cons :on plist :by #'cddr :unless (prog1 (bad-key-p (car the-cons)) (assert-proper-plist (cdr the-cons))) :do (return the-cons) :finally (return nil)))) (declare (inline assert-proper-plist bad-key-p find-first)) ;; Find the first good key and delete any bad key-value pairs ;; between it and the start. (let ((first (find-first))) (unless (eq first plist) (setf (cddr plist) first))
;; At this point, we know FIRST points to the first key ;; which exists, or NIL. (loop :with last-good := first ; Keep the last good key :for the-cons :on (cddr first) :by #'cddr :do (progn (assert-proper-plist (cdr the-cons)) (if (bad-key-p (car the-cons)) (setf (cddr last-good) (cddr the-cons)) (setf last-good the-cons))) :finally (return first)))))