github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/queues/circularbuffer/circularbuffer.go (about) 1 // Copyright (c) 2021, Emir Pasic. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package circularbuffer implements the circular buffer. 6 // 7 // In computer science, a circular buffer, circular queue, cyclic buffer or ring buffer is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. This structure lends itself easily to buffering data streams. 8 // 9 // Structure is not thread safe. 10 // 11 // Reference: https://en.wikipedia.org/wiki/Circular_buffer 12 package circularbuffer 13 14 import ( 15 "encoding/json" 16 "fmt" 17 "reflect" 18 "strings" 19 20 "github.com/songzhibin97/go-baseutils/structure/queues" 21 ) 22 23 // Assert Queue implementation 24 var _ queues.Queue[any] = (*Queue[any])(nil) 25 26 // Queue holds values in a slice. 27 type Queue[E any] struct { 28 values []E 29 start int 30 end int 31 full bool 32 maxSize int 33 size int 34 zero E 35 } 36 37 // New instantiates a new empty queue with the specified size of maximum number of elements that it can hold. 38 // This max size of the buffer cannot be changed. 39 func New[E any](maxSize int) *Queue[E] { 40 if maxSize < 1 { 41 panic("Invalid maxSize, should be at least 1") 42 } 43 queue := &Queue[E]{maxSize: maxSize} 44 queue.Clear() 45 return queue 46 } 47 48 // Enqueue adds a value to the end of the queue 49 func (queue *Queue[E]) Enqueue(value E) { 50 if queue.Full() { 51 queue.Dequeue() 52 } 53 queue.values[queue.end] = value 54 queue.end = queue.end + 1 55 if queue.end >= queue.maxSize { 56 queue.end = 0 57 } 58 if queue.end == queue.start { 59 queue.full = true 60 } 61 62 queue.size = queue.calculateSize() 63 } 64 65 // Dequeue removes first element of the queue and returns it, or nil if queue is empty. 66 // Second return parameter is true, unless the queue was empty and there was nothing to dequeue. 67 func (queue *Queue[E]) Dequeue() (value E, ok bool) { 68 if queue.Empty() { 69 return queue.zero, false 70 } 71 72 value, ok = queue.values[queue.start], true 73 74 if !reflect.DeepEqual(value, queue.zero) { 75 queue.values[queue.start] = queue.zero 76 queue.start = queue.start + 1 77 if queue.start >= queue.maxSize { 78 queue.start = 0 79 } 80 queue.full = false 81 } 82 83 queue.size = queue.size - 1 84 85 return 86 } 87 88 // Peek returns first element of the queue without removing it, or nil if queue is empty. 89 // Second return parameter is true, unless the queue was empty and there was nothing to peek. 90 func (queue *Queue[E]) Peek() (value E, ok bool) { 91 if queue.Empty() { 92 return queue.zero, false 93 } 94 return queue.values[queue.start], true 95 } 96 97 // Empty returns true if queue does not contain any elements. 98 func (queue *Queue[E]) Empty() bool { 99 return queue.Size() == 0 100 } 101 102 // Full returns true if the queue is full, i.e. has reached the maximum number of elements that it can hold. 103 func (queue *Queue[E]) Full() bool { 104 return queue.Size() == queue.maxSize 105 } 106 107 // Size returns number of elements within the queue. 108 func (queue *Queue[E]) Size() int { 109 return queue.size 110 } 111 112 // Clear removes all elements from the queue. 113 func (queue *Queue[E]) Clear() { 114 queue.values = make([]E, queue.maxSize, queue.maxSize) 115 queue.start = 0 116 queue.end = 0 117 queue.full = false 118 queue.size = 0 119 } 120 121 // Values returns all elements in the queue (FIFO order). 122 func (queue *Queue[E]) Values() []E { 123 values := make([]E, queue.Size(), queue.Size()) 124 for i := 0; i < queue.Size(); i++ { 125 values[i] = queue.values[(queue.start+i)%queue.maxSize] 126 } 127 return values 128 } 129 130 // String returns a string representation of container 131 func (queue *Queue[E]) String() string { 132 b := strings.Builder{} 133 b.WriteString("CircularBuffer\n") 134 for index, value := range queue.Values() { 135 b.WriteString(fmt.Sprintf("(index:%d value:%v) ", index, value)) 136 } 137 return b.String() 138 } 139 140 // Check that the index is within bounds of the list 141 func (queue *Queue[E]) withinRange(index int) bool { 142 return index >= 0 && index < queue.size 143 } 144 145 func (queue *Queue[E]) calculateSize() int { 146 if queue.end < queue.start { 147 return queue.maxSize - queue.start + queue.end 148 } else if queue.end == queue.start { 149 if queue.full { 150 return queue.maxSize 151 } 152 return 0 153 } 154 return queue.end - queue.start 155 } 156 157 // UnmarshalJSON @implements json.Unmarshaler 158 func (queue *Queue[E]) UnmarshalJSON(bytes []byte) error { 159 var values []E 160 err := json.Unmarshal(bytes, &values) 161 if err == nil { 162 for _, value := range values { 163 queue.Enqueue(value) 164 } 165 } 166 return err 167 } 168 169 // MarshalJSON @implements json.Marshaler 170 func (queue *Queue[E]) MarshalJSON() ([]byte, error) { 171 return json.Marshal(queue.values[:queue.maxSize]) 172 }