github.com/sandwich-go/boost@v1.3.29/xchan/ringbuffer.go (about)

     1  package xchan
     2  
     3  import (
     4  	"errors"
     5  )
     6  
     7  var ErrIsEmpty = errors.New("ring buffer is empty")
     8  
     9  // RingBuffer is a ring buffer for common types.
    10  // It never is full and always grows if it will be full.
    11  // It is not thread-safe(goroutine-safe) so you must use the lock-like synchronization primitive to use it in multiple writers and multiple readers.
    12  type RingBuffer[T any] struct {
    13  	buf         []T
    14  	initialSize int
    15  	size        int
    16  	r           int // read pointer
    17  	w           int // write pointer
    18  }
    19  
    20  func NewRingBuffer[T any](initialSize int) *RingBuffer[T] {
    21  	if initialSize <= 0 {
    22  		panic("initial size must be great than zero")
    23  	}
    24  	// initial size must >= 2
    25  	if initialSize == 1 {
    26  		initialSize = 2
    27  	}
    28  
    29  	return &RingBuffer[T]{
    30  		buf:         make([]T, initialSize),
    31  		initialSize: initialSize,
    32  		size:        initialSize,
    33  	}
    34  }
    35  
    36  func (r *RingBuffer[T]) Read() (T, error) {
    37  	var t T
    38  	if r.r == r.w {
    39  		return t, ErrIsEmpty
    40  	}
    41  
    42  	v := r.buf[r.r]
    43  	r.r++
    44  	if r.r == r.size {
    45  		r.r = 0
    46  	}
    47  
    48  	return v, nil
    49  }
    50  
    51  func (r *RingBuffer[T]) Pop() T {
    52  	v, err := r.Read()
    53  	if errors.Is(err, ErrIsEmpty) { // Empty
    54  		panic(ErrIsEmpty.Error())
    55  	}
    56  
    57  	return v
    58  }
    59  
    60  func (r *RingBuffer[T]) Peek() T {
    61  	if r.r == r.w { // Empty
    62  		panic(ErrIsEmpty.Error())
    63  	}
    64  
    65  	v := r.buf[r.r]
    66  	return v
    67  }
    68  
    69  func (r *RingBuffer[T]) Write(v T) {
    70  	r.buf[r.w] = v
    71  	r.w++
    72  
    73  	if r.w == r.size {
    74  		r.w = 0
    75  	}
    76  
    77  	if r.w == r.r { // full
    78  		r.grow()
    79  	}
    80  }
    81  
    82  func (r *RingBuffer[T]) grow() {
    83  	var size int
    84  	if r.size < 1024 {
    85  		size = r.size * 2
    86  	} else {
    87  		size = r.size + r.size/4
    88  	}
    89  
    90  	buf := make([]T, size)
    91  
    92  	copy(buf[0:], r.buf[r.r:])
    93  	copy(buf[r.size-r.r:], r.buf[0:r.r])
    94  
    95  	r.r = 0
    96  	r.w = r.size
    97  	r.size = size
    98  	r.buf = buf
    99  }
   100  
   101  func (r *RingBuffer[T]) IsEmpty() bool {
   102  	return r.r == r.w
   103  }
   104  
   105  // Capacity returns the size of the underlying buffer.
   106  func (r *RingBuffer[T]) Capacity() int {
   107  	return r.size
   108  }
   109  
   110  func (r *RingBuffer[T]) Len() int {
   111  	if r.r == r.w {
   112  		return 0
   113  	}
   114  
   115  	if r.w > r.r {
   116  		return r.w - r.r
   117  	}
   118  
   119  	return r.size - r.r + r.w
   120  }
   121  
   122  func (r *RingBuffer[T]) Reset() {
   123  	r.r = 0
   124  	r.w = 0
   125  	r.size = r.initialSize
   126  	r.buf = make([]T, r.initialSize)
   127  }