github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/ring/ring_buffer.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package ring 12 13 // Buffer is a deque maintained over a ring buffer. 14 // 15 // Note: it is backed by a slice (unlike container/ring which is backed by a 16 // linked list). 17 type Buffer struct { 18 buffer []interface{} 19 head int // the index of the front of the buffer 20 tail int // the index of the first position after the end of the buffer 21 22 // Indicates whether the buffer is empty. Necessary to distinguish 23 // between an empty buffer and a buffer that uses all of its capacity. 24 nonEmpty bool 25 } 26 27 // Len returns the number of elements in the Buffer. 28 func (r *Buffer) Len() int { 29 if !r.nonEmpty { 30 return 0 31 } 32 if r.head < r.tail { 33 return r.tail - r.head 34 } else if r.head == r.tail { 35 return cap(r.buffer) 36 } else { 37 return cap(r.buffer) + r.tail - r.head 38 } 39 } 40 41 // Cap returns the capacity of the Buffer. 42 func (r *Buffer) Cap() int { 43 return cap(r.buffer) 44 } 45 46 // Get returns an element at position pos in the Buffer (zero-based). 47 func (r *Buffer) Get(pos int) interface{} { 48 if !r.nonEmpty || pos < 0 || pos >= r.Len() { 49 panic("index out of bounds") 50 } 51 return r.buffer[(pos+r.head)%cap(r.buffer)] 52 } 53 54 // GetFirst returns an element at the front of the Buffer. 55 func (r *Buffer) GetFirst() interface{} { 56 if !r.nonEmpty { 57 panic("getting first from empty ring buffer") 58 } 59 return r.buffer[r.head] 60 } 61 62 // GetLast returns an element at the front of the Buffer. 63 func (r *Buffer) GetLast() interface{} { 64 if !r.nonEmpty { 65 panic("getting last from empty ring buffer") 66 } 67 return r.buffer[(cap(r.buffer)+r.tail-1)%cap(r.buffer)] 68 } 69 70 func (r *Buffer) grow(n int) { 71 newBuffer := make([]interface{}, n) 72 if r.head < r.tail { 73 copy(newBuffer[:r.Len()], r.buffer[r.head:r.tail]) 74 } else { 75 copy(newBuffer[:cap(r.buffer)-r.head], r.buffer[r.head:]) 76 copy(newBuffer[cap(r.buffer)-r.head:r.Len()], r.buffer[:r.tail]) 77 } 78 r.head = 0 79 r.tail = cap(r.buffer) 80 r.buffer = newBuffer 81 } 82 83 func (r *Buffer) maybeGrow() { 84 if r.Len() != cap(r.buffer) { 85 return 86 } 87 n := 2 * cap(r.buffer) 88 if n == 0 { 89 n = 1 90 } 91 r.grow(n) 92 } 93 94 // AddFirst add element to the front of the Buffer and doubles it's underlying 95 // slice if necessary. 96 func (r *Buffer) AddFirst(element interface{}) { 97 r.maybeGrow() 98 r.head = (cap(r.buffer) + r.head - 1) % cap(r.buffer) 99 r.buffer[r.head] = element 100 r.nonEmpty = true 101 } 102 103 // AddLast adds element to the end of the Buffer and doubles it's underlying 104 // slice if necessary. 105 func (r *Buffer) AddLast(element interface{}) { 106 r.maybeGrow() 107 r.buffer[r.tail] = element 108 r.tail = (r.tail + 1) % cap(r.buffer) 109 r.nonEmpty = true 110 } 111 112 // RemoveFirst removes a single element from the front of the Buffer. 113 func (r *Buffer) RemoveFirst() { 114 if r.Len() == 0 { 115 panic("removing first from empty ring buffer") 116 } 117 r.buffer[r.head] = nil 118 r.head = (r.head + 1) % cap(r.buffer) 119 if r.head == r.tail { 120 r.nonEmpty = false 121 } 122 } 123 124 // RemoveLast removes a single element from the end of the Buffer. 125 func (r *Buffer) RemoveLast() { 126 if r.Len() == 0 { 127 panic("removing last from empty ring buffer") 128 } 129 lastPos := (cap(r.buffer) + r.tail - 1) % cap(r.buffer) 130 r.buffer[lastPos] = nil 131 r.tail = lastPos 132 if r.tail == r.head { 133 r.nonEmpty = false 134 } 135 } 136 137 // Reserve reserves the provided number of elemnets in the Buffer. It is an 138 // error to reserve a size less than the Buffer's current length. 139 func (r *Buffer) Reserve(n int) { 140 if n < r.Len() { 141 panic("reserving fewer elements than current length") 142 } else if n > cap(r.buffer) { 143 r.grow(n) 144 } 145 } 146 147 // Reset makes Buffer treat its underlying memory as if it were empty. This 148 // allows for reusing the same memory again without explicitly removing old 149 // elements. 150 func (r *Buffer) Reset() { 151 r.head = 0 152 r.tail = 0 153 r.nonEmpty = false 154 }