github.com/blend/go-sdk@v1.20240719.1/collections/channel_queue.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 "sync" 11 12 // NewChannelQueueWithCapacity returns a new ChannelQueue instance. 13 func NewChannelQueueWithCapacity[T any](capacity int) *ChannelQueue[T] { 14 return &ChannelQueue[T]{Capacity: capacity, storage: make(chan T, capacity), latch: sync.Mutex{}} 15 } 16 17 // NewChannelQueueFromValues returns a new ChannelQueue from a given slice of values. 18 func NewChannelQueueFromValues[T any](values []T) *ChannelQueue[T] { 19 capacity := len(values) 20 cq := &ChannelQueue[T]{Capacity: capacity, storage: make(chan T, capacity), latch: sync.Mutex{}} 21 for _, v := range values { 22 cq.storage <- v 23 } 24 return cq 25 } 26 27 // ChannelQueue is a thread safe queue. 28 type ChannelQueue[T any] struct { 29 Capacity int 30 storage chan T 31 latch sync.Mutex 32 } 33 34 // Len returns the number of items in the queue. 35 func (cq *ChannelQueue[T]) Len() int { 36 return len(cq.storage) 37 } 38 39 // Enqueue adds an item to the queue. 40 func (cq *ChannelQueue[T]) Enqueue(item T) { 41 cq.storage <- item 42 } 43 44 // Dequeue returns the next element in the queue. 45 func (cq *ChannelQueue[T]) Dequeue() T { 46 var res T 47 if len(cq.storage) != 0 { 48 return <-cq.storage 49 } 50 return res 51 } 52 53 // DequeueBack iterates over the queue, removing the last element and returning it 54 func (cq *ChannelQueue[T]) DequeueBack() T { 55 var values []T 56 storageLen := len(cq.storage) 57 for x := 0; x < storageLen; x++ { 58 v := <-cq.storage 59 values = append(values, v) 60 } 61 var output T 62 for index, v := range values { 63 if index == len(values)-1 { 64 output = v 65 } else { 66 cq.storage <- v 67 } 68 } 69 return output 70 } 71 72 // Peek returns (but does not remove) the first element of the queue. 73 func (cq *ChannelQueue[T]) Peek() T { 74 var res T 75 if len(cq.storage) == 0 { 76 return res 77 } 78 return cq.Contents()[0] 79 } 80 81 // PeekBack returns (but does not remove) the last element of the queue. 82 func (cq *ChannelQueue[T]) PeekBack() T { 83 var res T 84 if len(cq.storage) == 0 { 85 return res 86 } 87 return cq.Contents()[len(cq.storage)-1] 88 } 89 90 // Clear clears the queue. 91 func (cq *ChannelQueue[T]) Clear() { 92 cq.storage = make(chan T, cq.Capacity) 93 } 94 95 // Each pulls every value out of the channel, calls consumer on it, and puts it back. 96 func (cq *ChannelQueue[T]) Each(consumer func(value T)) { 97 if len(cq.storage) == 0 { 98 return 99 } 100 var values []T 101 for len(cq.storage) != 0 { 102 v := <-cq.storage 103 consumer(v) 104 values = append(values, v) 105 } 106 for _, v := range values { 107 cq.storage <- v 108 } 109 } 110 111 // Consume pulls every value out of the channel, calls consumer on it, effectively clearing the queue. 112 func (cq *ChannelQueue[T]) Consume(consumer func(value T)) { 113 if len(cq.storage) == 0 { 114 return 115 } 116 for len(cq.storage) != 0 { 117 v := <-cq.storage 118 consumer(v) 119 } 120 } 121 122 // EachUntil pulls every value out of the channel, calls consumer on it, and puts it back and can abort mid-process. 123 func (cq *ChannelQueue[T]) EachUntil(consumer func(value T) bool) { 124 contents := cq.Contents() 125 for x := 0; x < len(contents); x++ { 126 if consumer(contents[x]) { 127 return 128 } 129 } 130 } 131 132 // ReverseEachUntil pulls every value out of the channel, calls consumer on it, and puts it back and can abort mid-process. 133 func (cq *ChannelQueue[T]) ReverseEachUntil(consumer func(value T) bool) { 134 contents := cq.Contents() 135 for x := len(contents) - 1; x >= 0; x-- { 136 if consumer(contents[x]) { 137 return 138 } 139 } 140 } 141 142 // Contents iterates over the queue and returns a slice of its contents. 143 func (cq *ChannelQueue[T]) Contents() []T { 144 var values []T 145 storageLen := len(cq.storage) 146 for x := 0; x < storageLen; x++ { 147 v := <-cq.storage 148 values = append(values, v) 149 } 150 for _, v := range values { 151 cq.storage <- v 152 } 153 return values 154 } 155 156 // Drain iterates over the queue and returns a slice of its contents, leaving it empty. 157 func (cq *ChannelQueue[T]) Drain() []T { 158 var values []T 159 for len(cq.storage) != 0 { 160 v := <-cq.storage 161 values = append(values, v) 162 } 163 return values 164 }