1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-28 08:11:05 -08:00

Rewritten. A poor choice of representation made the old code excessively

complex.  The new version is smaller and faster.  The interface is
unchanged, except that ring-remove now accepts an optional numeric argument
specifying the element to remove.
This commit is contained in:
Eric S. Raymond 1993-04-25 22:26:48 +00:00
parent 5b08a462d2
commit d3af54acef

View file

@ -24,15 +24,15 @@
;;; Commentary: ;;; Commentary:
;;; This code defines a ring data structure. A ring is a ;;; This code defines a ring data structure. A ring is a
;;; (hd-index tl-index . vector) ;;; (hd-index length . vector)
;;; list. You can insert to, remove from, and rotate a ring. When the ring ;;; list. You can insert to, remove from, and rotate a ring. When the ring
;;; fills up, insertions cause the oldest elts to be quietly dropped. ;;; fills up, insertions cause the oldest elts to be quietly dropped.
;;; ;;;
;;; In ring-ref, 0 is the index of the newest element. Higher indexes ;;; In ring-ref, 0 is the index of the newest element. Higher indexes
;;; correspond to older elements until they wrap. ;;; correspond to older elements until they wrap.
;;; ;;;
;;; HEAD = index of the newest item on the ring. ;;; hd-index = index of the newest item on the ring.
;;; TAIL = index of the oldest item on the ring. ;;; length = number of ring items.
;;; ;;;
;;; These functions are used by the input history mechanism, but they can ;;; These functions are used by the input history mechanism, but they can
;;; be used for other purposes as well. ;;; be used for other purposes as well.
@ -49,7 +49,7 @@
;;;###autoload ;;;###autoload
(defun make-ring (size) (defun make-ring (size)
"Make a ring that can contain SIZE elements." "Make a ring that can contain SIZE elements."
(cons 1 (cons 0 (make-vector (+ size 1) nil)))) (cons 0 (cons 0 (make-vector size nil))))
(defun ring-plus1 (index veclen) (defun ring-plus1 (index veclen)
"INDEX+1, with wraparound" "INDEX+1, with wraparound"
@ -62,29 +62,50 @@
(defun ring-length (ring) (defun ring-length (ring)
"Number of elements in the ring." "Number of elements in the ring."
(let ((hd (car ring)) (tl (car (cdr ring))) (siz (length (cdr (cdr ring))))) (car (cdr ring)))
(let ((len (if (<= hd tl) (+ 1 (- tl hd)) (+ 1 tl (- siz hd)))))
(if (= len siz) 0 len))))
(defun ring-empty-p (ring) (defun ring-empty-p (ring)
(= 0 (ring-length ring))) (= 0 (car (cdr ring))))
(defun ring-index (index head ringlen veclen)
(setq index (ring-mod index ringlen))
(ring-mod (1- (+ head (- ringlen index))) veclen))
(defun ring-insert (ring item) (defun ring-insert (ring item)
"Insert a new item onto the ring. If the ring is full, dump the oldest "Insert a new item onto the ring. If the ring is full, dump the oldest
item to make room." item to make room."
(let* ((vec (cdr (cdr ring))) (len (length vec)) (let* ((vec (cdr (cdr ring)))
(new-hd (ring-minus1 (car ring) len))) (veclen (length vec))
(setcar ring new-hd) (hd (car ring))
(aset vec new-hd item) (ln (car (cdr ring))))
(if (ring-empty-p ring) ;overflow -- dump one off the tail. (prog1
(setcar (cdr ring) (ring-minus1 (car (cdr ring)) len))))) (aset vec (ring-mod (+ hd ln) veclen) item)
(if (= ln veclen)
(setcar ring (ring-plus1 hd veclen))
(setcar (cdr ring) (1+ ln))))))
(defun ring-remove (ring) (defun ring-remove (ring &optional index)
"Remove the oldest item retained on the ring." "Remove an item from the RING. Return the removed item.
(if (ring-empty-p ring) (error "Ring empty") If optional INDEX is nil, remove the oldest item. If it's
(let ((tl (car (cdr ring))) (vec (cdr (cdr ring)))) numeric, remove the element indexed."
(setcar (cdr ring) (ring-minus1 tl (length vec))) (if (ring-empty-p ring)
(aref vec tl)))) (error "Ring empty")
(let* ((hd (car ring))
(ln (car (cdr ring)))
(vec (cdr (cdr ring)))
(veclen (length vec))
(tl (ring-mod (1- (+ hd ln)) veclen))
oldelt)
(if (null index)
(setq index (1- ln)))
(setq index (ring-index index hd ln veclen))
(setq oldelt (aref vec index))
(while (/= index tl)
(aset vec index (aref vec (ring-plus1 index veclen)))
(setq index (ring-plus1 index veclen)))
(aset vec tl nil)
(setcar (cdr ring) (1- ln))
oldelt)))
(defun ring-mod (n m) (defun ring-mod (n m)
"Returns N mod M. M is positive. "Returns N mod M. M is positive.
@ -99,12 +120,10 @@ Answer is guaranteed to be non-negative, and less than m."
INDEX need not be <= the ring length, the appropriate modulo operation INDEX need not be <= the ring length, the appropriate modulo operation
will be performed. Element 0 is the most recently inserted; higher indices will be performed. Element 0 is the most recently inserted; higher indices
correspond to older elements until they wrap." correspond to older elements until they wrap."
(let ((numelts (ring-length ring))) (if (ring-empty-p ring)
(if (= numelts 0) (error "indexed empty ring") (error "indexed empty ring")
(let* ((hd (car ring)) (tl (car (cdr ring))) (vec (cdr (cdr ring))) (let* ((hd (car ring)) (ln (car (cdr ring))) (vec (cdr (cdr ring))))
(index (ring-mod index numelts)) (aref vec (ring-index index hd ln (length vec))))))
(vec-index (ring-mod (+ index hd) (length vec))))
(aref vec vec-index)))))
(provide 'ring) (provide 'ring)