git.fiddlerwoaroof.com
Raw Blame History
(defpackage :data-lens.wrapped-sequence
  (:use :cl )
  (:export ))
(in-package :data-lens.wrapped-sequence)

(defgeneric underlying (wrapper)
  (:documentation "Return the underlying object of a wrapper"))

(defclass tagged-sequence (standard-object sequence)
  ((%underlying-sequence :initarg :underlying :accessor underlying)
   (%key-fn :initarg :key :reader key)
   (%invert-key :initarg :invert-key :reader invert-key)))

(defmethod sb-sequence:length ((sequence tagged-sequence))
  (length (underlying sequence)))

(defmethod sb-sequence:elt ((sequence tagged-sequence) index)
  (funcall (key sequence)
           (elt (underlying sequence)
                index)))

(defmethod (setf sb-sequence:elt) (new-value (sequence tagged-sequence) index)
  (setf (elt (underlying sequence)
             index)
        (funcall (invert-key sequence)
                 (elt (underlying sequence)
                      index)
                 new-value)))

(defmethod sb-sequence:adjust-sequence ((sequence tagged-sequence) length
                                        &rest r
                                        &key initial-element initial-contents)
  (declare (ignore initial-element initial-contents))
  (make-instance 'tagged-sequence
                 :underlying (apply #'sb-sequence:adjust-sequence
                                    (copy-seq (underlying sequence)) length
                                    r)
                 :key-fn (key sequence)
                 :invert-key (invert-key sequence)))

(defmethod sb-sequence:make-sequence-like
    ((sequence tagged-sequence) length &rest r)
  (apply #'sb-sequence:adjust-sequence sequence length r))

(defun wrap-sequence (seq key-fn invert-key-fn)
  (if invert-key-fn
      (make-instance 'tagged-sequence
                     :underlying seq
                     :key key-fn
                     :invert-key invert-key-fn)
      (make-instance 'tagged-sequence
                     :underlying seq
                     :key key-fn)))