summaryrefslogtreecommitdiffstats
path: root/src/container/ring/ring.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/container/ring/ring.go')
-rw-r--r--src/container/ring/ring.go136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/container/ring/ring.go b/src/container/ring/ring.go
new file mode 100644
index 0000000..268670b
--- /dev/null
+++ b/src/container/ring/ring.go
@@ -0,0 +1,136 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ring implements operations on circular lists.
+package ring
+
+// A Ring is an element of a circular list, or ring.
+// Rings do not have a beginning or end; a pointer to any ring element
+// serves as reference to the entire ring. Empty rings are represented
+// as nil Ring pointers. The zero value for a Ring is a one-element
+// ring with a nil Value.
+type Ring struct {
+ next, prev *Ring
+ Value any // for use by client; untouched by this library
+}
+
+func (r *Ring) init() *Ring {
+ r.next = r
+ r.prev = r
+ return r
+}
+
+// Next returns the next ring element. r must not be empty.
+func (r *Ring) Next() *Ring {
+ if r.next == nil {
+ return r.init()
+ }
+ return r.next
+}
+
+// Prev returns the previous ring element. r must not be empty.
+func (r *Ring) Prev() *Ring {
+ if r.next == nil {
+ return r.init()
+ }
+ return r.prev
+}
+
+// Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0)
+// in the ring and returns that ring element. r must not be empty.
+func (r *Ring) Move(n int) *Ring {
+ if r.next == nil {
+ return r.init()
+ }
+ switch {
+ case n < 0:
+ for ; n < 0; n++ {
+ r = r.prev
+ }
+ case n > 0:
+ for ; n > 0; n-- {
+ r = r.next
+ }
+ }
+ return r
+}
+
+// New creates a ring of n elements.
+func New(n int) *Ring {
+ if n <= 0 {
+ return nil
+ }
+ r := new(Ring)
+ p := r
+ for i := 1; i < n; i++ {
+ p.next = &Ring{prev: p}
+ p = p.next
+ }
+ p.next = r
+ r.prev = p
+ return r
+}
+
+// Link connects ring r with ring s such that r.Next()
+// becomes s and returns the original value for r.Next().
+// r must not be empty.
+//
+// If r and s point to the same ring, linking
+// them removes the elements between r and s from the ring.
+// The removed elements form a subring and the result is a
+// reference to that subring (if no elements were removed,
+// the result is still the original value for r.Next(),
+// and not nil).
+//
+// If r and s point to different rings, linking
+// them creates a single ring with the elements of s inserted
+// after r. The result points to the element following the
+// last element of s after insertion.
+func (r *Ring) Link(s *Ring) *Ring {
+ n := r.Next()
+ if s != nil {
+ p := s.Prev()
+ // Note: Cannot use multiple assignment because
+ // evaluation order of LHS is not specified.
+ r.next = s
+ s.prev = r
+ n.prev = p
+ p.next = n
+ }
+ return n
+}
+
+// Unlink removes n % r.Len() elements from the ring r, starting
+// at r.Next(). If n % r.Len() == 0, r remains unchanged.
+// The result is the removed subring. r must not be empty.
+func (r *Ring) Unlink(n int) *Ring {
+ if n <= 0 {
+ return nil
+ }
+ return r.Link(r.Move(n + 1))
+}
+
+// Len computes the number of elements in ring r.
+// It executes in time proportional to the number of elements.
+func (r *Ring) Len() int {
+ n := 0
+ if r != nil {
+ n = 1
+ for p := r.Next(); p != r; p = p.next {
+ n++
+ }
+ }
+ return n
+}
+
+// Do calls function f on each element of the ring, in forward order.
+// The behavior of Do is undefined if f changes *r.
+func (r *Ring) Do(f func(any)) {
+ if r != nil {
+ f(r.Value)
+ for p := r.Next(); p != r; p = p.next {
+ f(p.Value)
+ }
+ }
+}