github.com/MetalBlockchain/metalgo@v1.11.9/utils/buffer/unbounded_blocking_deque.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package buffer
     5  
     6  import (
     7  	"sync"
     8  
     9  	"github.com/MetalBlockchain/metalgo/utils"
    10  )
    11  
    12  var _ BlockingDeque[int] = (*unboundedBlockingDeque[int])(nil)
    13  
    14  type BlockingDeque[T any] interface {
    15  	Deque[T]
    16  
    17  	// Close and empty the deque.
    18  	Close()
    19  }
    20  
    21  // Returns a new unbounded deque with the given initial size.
    22  // Note that the returned deque is always empty -- [initSize] is just
    23  // a hint to prevent unnecessary resizing.
    24  func NewUnboundedBlockingDeque[T any](initSize int) BlockingDeque[T] {
    25  	q := &unboundedBlockingDeque[T]{
    26  		Deque: NewUnboundedDeque[T](initSize),
    27  	}
    28  	q.cond = sync.NewCond(&q.lock)
    29  	return q
    30  }
    31  
    32  type unboundedBlockingDeque[T any] struct {
    33  	lock   sync.RWMutex
    34  	cond   *sync.Cond
    35  	closed bool
    36  
    37  	Deque[T]
    38  }
    39  
    40  // If the deque is closed returns false.
    41  func (q *unboundedBlockingDeque[T]) PushRight(elt T) bool {
    42  	q.cond.L.Lock()
    43  	defer q.cond.L.Unlock()
    44  
    45  	if q.closed {
    46  		return false
    47  	}
    48  
    49  	// Add the item to the queue
    50  	q.Deque.PushRight(elt)
    51  
    52  	// Signal a waiting thread
    53  	q.cond.Signal()
    54  	return true
    55  }
    56  
    57  // If the deque is closed returns false.
    58  func (q *unboundedBlockingDeque[T]) PopRight() (T, bool) {
    59  	q.cond.L.Lock()
    60  	defer q.cond.L.Unlock()
    61  
    62  	for {
    63  		if q.closed {
    64  			return utils.Zero[T](), false
    65  		}
    66  		if q.Deque.Len() != 0 {
    67  			return q.Deque.PopRight()
    68  		}
    69  		q.cond.Wait()
    70  	}
    71  }
    72  
    73  func (q *unboundedBlockingDeque[T]) PeekRight() (T, bool) {
    74  	q.lock.RLock()
    75  	defer q.lock.RUnlock()
    76  
    77  	if q.closed {
    78  		return utils.Zero[T](), false
    79  	}
    80  	return q.Deque.PeekRight()
    81  }
    82  
    83  // If the deque is closed returns false.
    84  func (q *unboundedBlockingDeque[T]) PushLeft(elt T) bool {
    85  	q.cond.L.Lock()
    86  	defer q.cond.L.Unlock()
    87  
    88  	if q.closed {
    89  		return false
    90  	}
    91  
    92  	// Add the item to the queue
    93  	q.Deque.PushLeft(elt)
    94  
    95  	// Signal a waiting thread
    96  	q.cond.Signal()
    97  	return true
    98  }
    99  
   100  // If the deque is closed returns false.
   101  func (q *unboundedBlockingDeque[T]) PopLeft() (T, bool) {
   102  	q.cond.L.Lock()
   103  	defer q.cond.L.Unlock()
   104  
   105  	for {
   106  		if q.closed {
   107  			return utils.Zero[T](), false
   108  		}
   109  		if q.Deque.Len() != 0 {
   110  			return q.Deque.PopLeft()
   111  		}
   112  		q.cond.Wait()
   113  	}
   114  }
   115  
   116  func (q *unboundedBlockingDeque[T]) PeekLeft() (T, bool) {
   117  	q.lock.RLock()
   118  	defer q.lock.RUnlock()
   119  
   120  	if q.closed {
   121  		return utils.Zero[T](), false
   122  	}
   123  	return q.Deque.PeekLeft()
   124  }
   125  
   126  func (q *unboundedBlockingDeque[T]) Index(i int) (T, bool) {
   127  	q.lock.RLock()
   128  	defer q.lock.RUnlock()
   129  
   130  	if q.closed {
   131  		return utils.Zero[T](), false
   132  	}
   133  	return q.Deque.Index(i)
   134  }
   135  
   136  func (q *unboundedBlockingDeque[T]) Len() int {
   137  	q.lock.RLock()
   138  	defer q.lock.RUnlock()
   139  
   140  	if q.closed {
   141  		return 0
   142  	}
   143  	return q.Deque.Len()
   144  }
   145  
   146  func (q *unboundedBlockingDeque[T]) List() []T {
   147  	q.lock.RLock()
   148  	defer q.lock.RUnlock()
   149  
   150  	if q.closed {
   151  		return nil
   152  	}
   153  	return q.Deque.List()
   154  }
   155  
   156  func (q *unboundedBlockingDeque[T]) Close() {
   157  	q.cond.L.Lock()
   158  	defer q.cond.L.Unlock()
   159  
   160  	if q.closed {
   161  		return
   162  	}
   163  
   164  	q.Deque = nil
   165  
   166  	// Mark the queue as closed
   167  	q.closed = true
   168  	q.cond.Broadcast()
   169  }