github.com/blend/go-sdk@v1.20220411.3/collections/channel_queue.go (about)

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