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  }