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 }