summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp/ring.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-lisp/ring.el')
-rw-r--r--lisp/emacs-lisp/ring.el110
1 files changed, 90 insertions, 20 deletions
diff --git a/lisp/emacs-lisp/ring.el b/lisp/emacs-lisp/ring.el
index 2c8e0a29faf..d9ce48e23a6 100644
--- a/lisp/emacs-lisp/ring.el
+++ b/lisp/emacs-lisp/ring.el
@@ -51,8 +51,8 @@
(defun ring-p (x)
"Return t if X is a ring; nil otherwise."
(and (consp x) (integerp (car x))
- (consp (cdr x)) (integerp (car (cdr x)))
- (vectorp (cdr (cdr x)))))
+ (consp (cdr x)) (integerp (cadr x))
+ (vectorp (cddr x))))
;;;###autoload
(defun make-ring (size)
@@ -60,11 +60,11 @@
(cons 0 (cons 0 (make-vector size nil))))
(defun ring-insert-at-beginning (ring item)
- "Add to RING the item ITEM. Add it at the front, as the oldest item."
- (let* ((vec (cdr (cdr ring)))
+ "Add to RING the item ITEM, at the front, as the oldest item."
+ (let* ((vec (cddr ring))
(veclen (length vec))
(hd (car ring))
- (ln (car (cdr ring))))
+ (ln (cadr ring)))
(setq ln (min veclen (1+ ln))
hd (ring-minus1 hd veclen))
(aset vec hd item)
@@ -73,16 +73,16 @@
(defun ring-plus1 (index veclen)
"Return INDEX+1, with wraparound."
- (let ((new-index (+ index 1)))
+ (let ((new-index (1+ index)))
(if (= new-index veclen) 0 new-index)))
(defun ring-minus1 (index veclen)
"Return INDEX-1, with wraparound."
- (- (if (= 0 index) veclen index) 1))
+ (- (if (zerop index) veclen index) 1))
(defun ring-length (ring)
"Return the number of elements in the RING."
- (car (cdr ring)))
+ (cadr ring))
(defun ring-index (index head ringlen veclen)
"Convert nominal ring index INDEX to an internal index.
@@ -95,26 +95,26 @@ VECLEN is the size of the vector in the ring."
(defun ring-empty-p (ring)
"Return t if RING is empty; nil otherwise."
- (zerop (car (cdr ring))))
+ (zerop (cadr ring)))
(defun ring-size (ring)
"Return the size of RING, the maximum number of elements it can contain."
- (length (cdr (cdr ring))))
+ (length (cddr ring)))
(defun ring-copy (ring)
"Return a copy of RING."
- (let* ((vec (cdr (cdr ring)))
- (hd (car ring))
- (ln (car (cdr ring))))
+ (let ((vec (cddr ring))
+ (hd (car ring))
+ (ln (cadr ring)))
(cons hd (cons ln (copy-sequence vec)))))
(defun ring-insert (ring item)
"Insert onto ring RING the item ITEM, as the newest (last) item.
If the ring is full, dump the oldest item to make room."
- (let* ((vec (cdr (cdr ring)))
+ (let* ((vec (cddr ring))
(veclen (length vec))
(hd (car ring))
- (ln (car (cdr ring))))
+ (ln (cadr ring)))
(prog1
(aset vec (mod (+ hd ln) veclen) item)
(if (= ln veclen)
@@ -128,13 +128,13 @@ numeric, remove the element indexed."
(if (ring-empty-p ring)
(error "Ring empty")
(let* ((hd (car ring))
- (ln (car (cdr ring)))
- (vec (cdr (cdr ring)))
+ (ln (cadr ring))
+ (vec (cddr ring))
(veclen (length vec))
(tl (mod (1- (+ hd ln)) veclen))
oldelt)
- (if (null index)
- (setq index (1- ln)))
+ (when (null index)
+ (setq index (1- ln)))
(setq index (ring-index index hd ln veclen))
(setq oldelt (aref vec index))
(while (/= index tl)
@@ -152,7 +152,9 @@ INDEX need not be <= the ring length; the appropriate modulo operation
will be performed."
(if (ring-empty-p ring)
(error "Accessing an empty ring")
- (let* ((hd (car ring)) (ln (car (cdr ring))) (vec (cdr (cdr ring))))
+ (let ((hd (car ring))
+ (ln (cadr ring))
+ (vec (cddr ring)))
(aref vec (ring-index index hd ln (length vec))))))
(defun ring-elements (ring)
@@ -164,6 +166,74 @@ will be performed."
(dotimes (var (cadr ring) lst)
(push (aref vect (mod (+ start var) size)) lst))))
+(defun ring-member (ring item)
+ "Return index of ITEM if on RING, else nil.
+Comparison is done via `equal'. The index is 0-based."
+ (catch 'found
+ (dotimes (ind (ring-length ring) nil)
+ (when (equal item (ring-ref ring ind))
+ (throw 'found ind)))))
+
+(defun ring-next (ring item)
+ "Return the next item in the RING, after ITEM.
+Raise error if ITEM is not in the RING."
+ (let ((curr-index (ring-member ring item)))
+ (unless curr-index (error "Item is not in the ring: `%s'" item))
+ (ring-ref ring (ring-plus1 curr-index (ring-length ring)))))
+
+(defun ring-previous (ring item)
+ "Return the previous item in the RING, before ITEM.
+Raise error if ITEM is not in the RING."
+ (let ((curr-index (ring-member ring item)))
+ (unless curr-index (error "Item is not in the ring: `%s'" item))
+ (ring-ref ring (ring-minus1 curr-index (ring-length ring)))))
+
+(defun ring-insert+extend (ring item &optional grow-p)
+ "Like `ring-insert', but if GROW-P is non-nil, then enlarge ring.
+Insert onto ring RING the item ITEM, as the newest (last) item.
+If the ring is full, behavior depends on GROW-P:
+ If GROW-P is non-nil, enlarge the ring to accommodate the new item.
+ If GROW-P is nil, dump the oldest item to make room for the new."
+ (let* ((vec (cddr ring))
+ (veclen (length vec))
+ (hd (car ring))
+ (ringlen (ring-length ring)))
+ (prog1
+ (cond ((and grow-p (= ringlen veclen)) ; Full ring. Enlarge it.
+ (setq veclen (1+ veclen))
+ (setcdr ring (cons (setq ringlen (1+ ringlen))
+ (setq vec (vconcat vec (vector item)))))
+ (setcar ring hd))
+ (t (aset vec (mod (+ hd ringlen) veclen) item)))
+ (if (= ringlen veclen)
+ (setcar ring (ring-plus1 hd veclen))
+ (setcar (cdr ring) (1+ ringlen))))))
+
+(defun ring-remove+insert+extend (ring item &optional grow-p)
+ "`ring-remove' ITEM from RING, then `ring-insert+extend' it.
+This ensures that there is only one ITEM on RING.
+
+If the RING is full, behavior depends on GROW-P:
+ If GROW-P is non-nil, enlarge the ring to accommodate the new ITEM.
+ If GROW-P is nil, dump the oldest item to make room for the new."
+ (let (ind)
+ (while (setq ind (ring-member ring item))
+ (ring-remove ring ind)))
+ (ring-insert+extend ring item grow-p))
+
+(defun ring-convert-sequence-to-ring (seq)
+ "Convert sequence SEQ to a ring. Return the ring.
+If SEQ is already a ring, return it."
+ (if (ring-p seq)
+ seq
+ (let* ((size (length seq))
+ (ring (make-ring size)))
+ (dotimes (count size)
+ (when (or (ring-empty-p ring)
+ (not (equal (ring-ref ring 0) (elt seq count))))
+ (ring-insert-at-beginning ring (elt seq count))))
+ ring)))
+
;;; provide ourself:
(provide 'ring)