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  }