diff options
| author | Eric S. Raymond | 1993-04-25 22:26:48 +0000 |
|---|---|---|
| committer | Eric S. Raymond | 1993-04-25 22:26:48 +0000 |
| commit | d3af54acef262f6340231fb409978374dc91716c (patch) | |
| tree | c81b2d6eb2b2541f80e837d41c2274fc94bc070e | |
| parent | 5b08a462d2e2cb35cd8dbe1d3bcb275883cfa997 (diff) | |
| download | emacs-d3af54acef262f6340231fb409978374dc91716c.tar.gz emacs-d3af54acef262f6340231fb409978374dc91716c.zip | |
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.
| -rw-r--r-- | lisp/emacs-lisp/ring.el | 73 |
1 files changed, 46 insertions, 27 deletions
diff --git a/lisp/emacs-lisp/ring.el b/lisp/emacs-lisp/ring.el index eedc801e16a..28f568d17fd 100644 --- a/lisp/emacs-lisp/ring.el +++ b/lisp/emacs-lisp/ring.el | |||
| @@ -24,15 +24,15 @@ | |||
| 24 | ;;; Commentary: | 24 | ;;; Commentary: |
| 25 | 25 | ||
| 26 | ;;; This code defines a ring data structure. A ring is a | 26 | ;;; This code defines a ring data structure. A ring is a |
| 27 | ;;; (hd-index tl-index . vector) | 27 | ;;; (hd-index length . vector) |
| 28 | ;;; list. You can insert to, remove from, and rotate a ring. When the ring | 28 | ;;; list. You can insert to, remove from, and rotate a ring. When the ring |
| 29 | ;;; fills up, insertions cause the oldest elts to be quietly dropped. | 29 | ;;; fills up, insertions cause the oldest elts to be quietly dropped. |
| 30 | ;;; | 30 | ;;; |
| 31 | ;;; In ring-ref, 0 is the index of the newest element. Higher indexes | 31 | ;;; In ring-ref, 0 is the index of the newest element. Higher indexes |
| 32 | ;;; correspond to older elements until they wrap. | 32 | ;;; correspond to older elements until they wrap. |
| 33 | ;;; | 33 | ;;; |
| 34 | ;;; HEAD = index of the newest item on the ring. | 34 | ;;; hd-index = index of the newest item on the ring. |
| 35 | ;;; TAIL = index of the oldest item on the ring. | 35 | ;;; length = number of ring items. |
| 36 | ;;; | 36 | ;;; |
| 37 | ;;; These functions are used by the input history mechanism, but they can | 37 | ;;; These functions are used by the input history mechanism, but they can |
| 38 | ;;; be used for other purposes as well. | 38 | ;;; be used for other purposes as well. |
| @@ -49,7 +49,7 @@ | |||
| 49 | ;;;###autoload | 49 | ;;;###autoload |
| 50 | (defun make-ring (size) | 50 | (defun make-ring (size) |
| 51 | "Make a ring that can contain SIZE elements." | 51 | "Make a ring that can contain SIZE elements." |
| 52 | (cons 1 (cons 0 (make-vector (+ size 1) nil)))) | 52 | (cons 0 (cons 0 (make-vector size nil)))) |
| 53 | 53 | ||
| 54 | (defun ring-plus1 (index veclen) | 54 | (defun ring-plus1 (index veclen) |
| 55 | "INDEX+1, with wraparound" | 55 | "INDEX+1, with wraparound" |
| @@ -62,29 +62,50 @@ | |||
| 62 | 62 | ||
| 63 | (defun ring-length (ring) | 63 | (defun ring-length (ring) |
| 64 | "Number of elements in the ring." | 64 | "Number of elements in the ring." |
| 65 | (let ((hd (car ring)) (tl (car (cdr ring))) (siz (length (cdr (cdr ring))))) | 65 | (car (cdr ring))) |
| 66 | (let ((len (if (<= hd tl) (+ 1 (- tl hd)) (+ 1 tl (- siz hd))))) | ||
| 67 | (if (= len siz) 0 len)))) | ||
| 68 | 66 | ||
| 69 | (defun ring-empty-p (ring) | 67 | (defun ring-empty-p (ring) |
| 70 | (= 0 (ring-length ring))) | 68 | (= 0 (car (cdr ring)))) |
| 69 | |||
| 70 | (defun ring-index (index head ringlen veclen) | ||
| 71 | (setq index (ring-mod index ringlen)) | ||
| 72 | (ring-mod (1- (+ head (- ringlen index))) veclen)) | ||
| 71 | 73 | ||
| 72 | (defun ring-insert (ring item) | 74 | (defun ring-insert (ring item) |
| 73 | "Insert a new item onto the ring. If the ring is full, dump the oldest | 75 | "Insert a new item onto the ring. If the ring is full, dump the oldest |
| 74 | item to make room." | 76 | item to make room." |
| 75 | (let* ((vec (cdr (cdr ring))) (len (length vec)) | 77 | (let* ((vec (cdr (cdr ring))) |
| 76 | (new-hd (ring-minus1 (car ring) len))) | 78 | (veclen (length vec)) |
| 77 | (setcar ring new-hd) | 79 | (hd (car ring)) |
| 78 | (aset vec new-hd item) | 80 | (ln (car (cdr ring)))) |
| 79 | (if (ring-empty-p ring) ;overflow -- dump one off the tail. | 81 | (prog1 |
| 80 | (setcar (cdr ring) (ring-minus1 (car (cdr ring)) len))))) | 82 | (aset vec (ring-mod (+ hd ln) veclen) item) |
| 81 | 83 | (if (= ln veclen) | |
| 82 | (defun ring-remove (ring) | 84 | (setcar ring (ring-plus1 hd veclen)) |
| 83 | "Remove the oldest item retained on the ring." | 85 | (setcar (cdr ring) (1+ ln)))))) |
| 84 | (if (ring-empty-p ring) (error "Ring empty") | 86 | |
| 85 | (let ((tl (car (cdr ring))) (vec (cdr (cdr ring)))) | 87 | (defun ring-remove (ring &optional index) |
| 86 | (setcar (cdr ring) (ring-minus1 tl (length vec))) | 88 | "Remove an item from the RING. Return the removed item. |
| 87 | (aref vec tl)))) | 89 | If optional INDEX is nil, remove the oldest item. If it's |
| 90 | numeric, remove the element indexed." | ||
| 91 | (if (ring-empty-p ring) | ||
| 92 | (error "Ring empty") | ||
| 93 | (let* ((hd (car ring)) | ||
| 94 | (ln (car (cdr ring))) | ||
| 95 | (vec (cdr (cdr ring))) | ||
| 96 | (veclen (length vec)) | ||
| 97 | (tl (ring-mod (1- (+ hd ln)) veclen)) | ||
| 98 | oldelt) | ||
| 99 | (if (null index) | ||
| 100 | (setq index (1- ln))) | ||
| 101 | (setq index (ring-index index hd ln veclen)) | ||
| 102 | (setq oldelt (aref vec index)) | ||
| 103 | (while (/= index tl) | ||
| 104 | (aset vec index (aref vec (ring-plus1 index veclen))) | ||
| 105 | (setq index (ring-plus1 index veclen))) | ||
| 106 | (aset vec tl nil) | ||
| 107 | (setcar (cdr ring) (1- ln)) | ||
| 108 | oldelt))) | ||
| 88 | 109 | ||
| 89 | (defun ring-mod (n m) | 110 | (defun ring-mod (n m) |
| 90 | "Returns N mod M. M is positive. | 111 | "Returns N mod M. M is positive. |
| @@ -99,12 +120,10 @@ Answer is guaranteed to be non-negative, and less than m." | |||
| 99 | INDEX need not be <= the ring length, the appropriate modulo operation | 120 | INDEX need not be <= the ring length, the appropriate modulo operation |
| 100 | will be performed. Element 0 is the most recently inserted; higher indices | 121 | will be performed. Element 0 is the most recently inserted; higher indices |
| 101 | correspond to older elements until they wrap." | 122 | correspond to older elements until they wrap." |
| 102 | (let ((numelts (ring-length ring))) | 123 | (if (ring-empty-p ring) |
| 103 | (if (= numelts 0) (error "indexed empty ring") | 124 | (error "indexed empty ring") |
| 104 | (let* ((hd (car ring)) (tl (car (cdr ring))) (vec (cdr (cdr ring))) | 125 | (let* ((hd (car ring)) (ln (car (cdr ring))) (vec (cdr (cdr ring)))) |
| 105 | (index (ring-mod index numelts)) | 126 | (aref vec (ring-index index hd ln (length vec)))))) |
| 106 | (vec-index (ring-mod (+ index hd) (length vec)))) | ||
| 107 | (aref vec vec-index))))) | ||
| 108 | 127 | ||
| 109 | (provide 'ring) | 128 | (provide 'ring) |
| 110 | 129 | ||