github.com/blend/go-sdk@v1.20240719.1/collections/sync_ring_buffer.go (about)

     1  /*
     2  
     3  Copyright (c) 2024 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package collections
     9  
    10  import (
    11  	"sync"
    12  )
    13  
    14  // NewSyncRingBuffer returns a new synchronized ring buffer.
    15  func NewSyncRingBuffer[T any]() *SyncRingBuffer[T] {
    16  	return &SyncRingBuffer[T]{
    17  		innerBuffer: NewRingBuffer[T](),
    18  		syncRoot:    &sync.Mutex{},
    19  	}
    20  }
    21  
    22  // NewSyncRingBufferWithCapacity returns a new synchronized ring buffer.
    23  func NewSyncRingBufferWithCapacity[T any](capacity int) *SyncRingBuffer[T] {
    24  	return &SyncRingBuffer[T]{
    25  		innerBuffer: NewRingBufferWithCapacity[T](capacity),
    26  		syncRoot:    &sync.Mutex{},
    27  	}
    28  }
    29  
    30  // SyncRingBuffer is a ring buffer wrapper that adds synchronization.
    31  type SyncRingBuffer[T any] struct {
    32  	innerBuffer *RingBuffer[T]
    33  	syncRoot    *sync.Mutex
    34  }
    35  
    36  // SyncRoot returns the mutex used to synchronize the collection.
    37  func (srb *SyncRingBuffer[T]) SyncRoot() *sync.Mutex {
    38  	return srb.syncRoot
    39  }
    40  
    41  // RingBuffer returns the inner ring buffer.
    42  func (srb *SyncRingBuffer[T]) RingBuffer() *RingBuffer[T] {
    43  	return srb.innerBuffer
    44  }
    45  
    46  // Len returns the length of the ring buffer (as it is currently populated).
    47  // Actual memory footprint may be different.
    48  func (srb SyncRingBuffer[T]) Len() int {
    49  	srb.syncRoot.Lock()
    50  	defer srb.syncRoot.Unlock()
    51  	return srb.innerBuffer.Len()
    52  }
    53  
    54  // Capacity returns the total size of the ring buffer, including empty elements.
    55  func (srb *SyncRingBuffer[T]) Capacity() int {
    56  	srb.syncRoot.Lock()
    57  	defer srb.syncRoot.Unlock()
    58  	return srb.innerBuffer.Capacity()
    59  }
    60  
    61  // Enqueue adds an element to the "back" of the ring buffer.
    62  func (srb *SyncRingBuffer[T]) Enqueue(value T) {
    63  	srb.syncRoot.Lock()
    64  	srb.innerBuffer.Enqueue(value)
    65  	srb.syncRoot.Unlock()
    66  }
    67  
    68  // Dequeue removes the first (oldest) element from the ring buffer.
    69  func (srb *SyncRingBuffer[T]) Dequeue() T {
    70  	var val T
    71  	srb.syncRoot.Lock()
    72  	val = srb.innerBuffer.Dequeue()
    73  	srb.syncRoot.Unlock()
    74  	return val
    75  }
    76  
    77  // DequeueBack removes the last (newest) element from the ring buffer.
    78  func (srb *SyncRingBuffer[T]) DequeueBack() T {
    79  	var val T
    80  	srb.syncRoot.Lock()
    81  	val = srb.innerBuffer.DequeueBack()
    82  	srb.syncRoot.Unlock()
    83  	return val
    84  }
    85  
    86  // Peek returns but does not remove the first element.
    87  func (srb *SyncRingBuffer[T]) Peek() T {
    88  	var val T
    89  	srb.syncRoot.Lock()
    90  	val = srb.innerBuffer.Peek()
    91  	srb.syncRoot.Unlock()
    92  	return val
    93  }
    94  
    95  // PeekBack returns but does not remove the last element.
    96  func (srb *SyncRingBuffer[T]) PeekBack() T {
    97  	var val T
    98  	srb.syncRoot.Lock()
    99  	val = srb.innerBuffer.PeekBack()
   100  	srb.syncRoot.Unlock()
   101  	return val
   102  }
   103  
   104  // TrimExcess resizes the buffer to better fit the contents.
   105  func (srb *SyncRingBuffer[T]) TrimExcess() {
   106  	srb.syncRoot.Lock()
   107  	srb.innerBuffer.trimExcess()
   108  	srb.syncRoot.Unlock()
   109  }
   110  
   111  // Contents returns the ring buffer, in order, as a slice.
   112  func (srb *SyncRingBuffer[T]) Contents() []T {
   113  	var val []T
   114  	srb.syncRoot.Lock()
   115  	val = srb.innerBuffer.Contents()
   116  	srb.syncRoot.Unlock()
   117  	return val
   118  }
   119  
   120  // Clear removes all objects from the ring buffer.
   121  func (srb *SyncRingBuffer[T]) Clear() {
   122  	srb.syncRoot.Lock()
   123  	srb.innerBuffer.Clear()
   124  	srb.syncRoot.Unlock()
   125  }
   126  
   127  // Drain returns the ring buffer, in order, as a slice and empties it.
   128  func (srb *SyncRingBuffer[T]) Drain() []T {
   129  	var val []T
   130  	srb.syncRoot.Lock()
   131  	val = srb.innerBuffer.Drain()
   132  	srb.syncRoot.Unlock()
   133  	return val
   134  }
   135  
   136  // Each calls the consumer for each element in the buffer.
   137  func (srb *SyncRingBuffer[T]) Each(consumer func(value T)) {
   138  	srb.syncRoot.Lock()
   139  	srb.innerBuffer.Each(consumer)
   140  	srb.syncRoot.Unlock()
   141  }
   142  
   143  // Consume calls the consumer for each element in the buffer, while also dequeueing that entry.
   144  func (srb *SyncRingBuffer[T]) Consume(consumer func(value T)) {
   145  	srb.syncRoot.Lock()
   146  	srb.innerBuffer.Consume(consumer)
   147  	srb.syncRoot.Unlock()
   148  }
   149  
   150  // EachUntil calls the consumer for each element in the buffer with a stopping condition in head=>tail order.
   151  func (srb *SyncRingBuffer[T]) EachUntil(consumer func(value T) bool) {
   152  	srb.syncRoot.Lock()
   153  	srb.innerBuffer.EachUntil(consumer)
   154  	srb.syncRoot.Unlock()
   155  }
   156  
   157  // ReverseEachUntil calls the consumer for each element in the buffer with a stopping condition in tail=>head order.
   158  func (srb *SyncRingBuffer[T]) ReverseEachUntil(consumer func(value T) bool) {
   159  	srb.syncRoot.Lock()
   160  	srb.innerBuffer.ReverseEachUntil(consumer)
   161  	srb.syncRoot.Unlock()
   162  }