github.com/blend/go-sdk@v1.20240719.1/collections/linked_list.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  // NewLinkedList returns a new linked list instance.
    11  func NewLinkedList[T any]() *LinkedList[T] {
    12  	return &LinkedList[T]{}
    13  }
    14  
    15  // NewLinkedListFromValues creates a linked list out of a slice.
    16  func NewLinkedListFromValues[T any](values []T) *LinkedList[T] {
    17  	list := new(LinkedList[T])
    18  	for _, v := range values {
    19  		list.Enqueue(v)
    20  	}
    21  	return list
    22  }
    23  
    24  // LinkedList is an implementation of a fifo buffer using nodes and pointers.
    25  // Remarks; it is not thread safe. It is constant(ish) time in all ops.
    26  type LinkedList[T any] struct {
    27  	head   *listNode[T]
    28  	tail   *listNode[T]
    29  	length int
    30  }
    31  
    32  // Len returns the length of the queue in constant time.
    33  func (q *LinkedList[T]) Len() int {
    34  	return q.length
    35  }
    36  
    37  // Enqueue adds a new value to the queue.
    38  func (q *LinkedList[T]) Enqueue(value T) {
    39  	node := &listNode[T]{Value: value}
    40  
    41  	if q.head == nil { // the queue is empty, that is to say head is nil
    42  		q.head = node
    43  		q.tail = node
    44  	} else { // the queue is not empty, we have a (valid) tail pointer
    45  		q.tail.Previous = node
    46  		node.Next = q.tail
    47  		q.tail = node
    48  	}
    49  
    50  	q.length++
    51  }
    52  
    53  // Dequeue removes an item from the front of the queue and returns it.
    54  func (q *LinkedList[T]) Dequeue() T {
    55  	var res T
    56  	if q.head == nil {
    57  		return res
    58  	}
    59  
    60  	headValue := q.head.Value
    61  
    62  	if q.length == 1 && q.head == q.tail {
    63  		q.head = nil
    64  		q.tail = nil
    65  	} else {
    66  		q.head = q.head.Previous
    67  		if q.head != nil {
    68  			q.head.Next = nil
    69  		}
    70  	}
    71  
    72  	q.length--
    73  	return headValue
    74  }
    75  
    76  // DequeueBack pops the _last_ element off the linked list.
    77  func (q *LinkedList[T]) DequeueBack() T {
    78  	var res T
    79  	if q.tail == nil {
    80  		return res
    81  	}
    82  	tailValue := q.tail.Value
    83  
    84  	if q.length == 1 {
    85  		q.head = nil
    86  		q.tail = nil
    87  	} else {
    88  		q.tail = q.tail.Next
    89  		if q.tail != nil {
    90  			q.tail.Previous = nil
    91  		}
    92  	}
    93  
    94  	q.length--
    95  	return tailValue
    96  }
    97  
    98  // Peek returns the first element of the queue but does not remove it.
    99  func (q *LinkedList[T]) Peek() T {
   100  	var res T
   101  	if q.head == nil {
   102  		return res
   103  	}
   104  	return q.head.Value
   105  }
   106  
   107  // PeekBack returns the last element of the queue.
   108  func (q *LinkedList[T]) PeekBack() T {
   109  	var res T
   110  	if q.tail == nil {
   111  		return res
   112  	}
   113  	return q.tail.Value
   114  }
   115  
   116  // Clear clears the linked list.
   117  func (q *LinkedList[T]) Clear() {
   118  	q.tail = nil
   119  	q.head = nil
   120  	q.length = 0
   121  }
   122  
   123  // Drain calls the consumer for each element of the linked list.
   124  func (q *LinkedList[T]) Drain() []T {
   125  	if q.head == nil {
   126  		return nil
   127  	}
   128  
   129  	contents := make([]T, q.length)
   130  	nodePtr := q.head
   131  	index := 0
   132  	for nodePtr != nil {
   133  		contents[index] = nodePtr.Value
   134  		nodePtr = nodePtr.Previous
   135  		index++
   136  	}
   137  	q.tail = nil
   138  	q.head = nil
   139  	q.length = 0
   140  	return contents
   141  }
   142  
   143  // Each calls the consumer for each element of the linked list.
   144  func (q *LinkedList[T]) Each(consumer func(value T)) {
   145  	if q.head == nil {
   146  		return
   147  	}
   148  
   149  	nodePtr := q.head
   150  	for nodePtr != nil {
   151  		consumer(nodePtr.Value)
   152  		nodePtr = nodePtr.Previous
   153  	}
   154  }
   155  
   156  // Consume calls the consumer for each element of the linked list, removing it.
   157  func (q *LinkedList[T]) Consume(consumer func(value T)) {
   158  	if q.head == nil {
   159  		return
   160  	}
   161  
   162  	nodePtr := q.head
   163  	for nodePtr != nil {
   164  		consumer(nodePtr.Value)
   165  		nodePtr = nodePtr.Previous
   166  	}
   167  	q.tail = nil
   168  	q.head = nil
   169  	q.length = 0
   170  }
   171  
   172  // EachUntil calls the consumer for each element of the linked list, but can abort.
   173  func (q *LinkedList[T]) EachUntil(consumer func(value T) bool) {
   174  	if q.head == nil {
   175  		return
   176  	}
   177  
   178  	nodePtr := q.head
   179  	for nodePtr != nil {
   180  		if !consumer(nodePtr.Value) {
   181  			return
   182  		}
   183  		nodePtr = nodePtr.Previous
   184  	}
   185  }
   186  
   187  // ReverseEachUntil calls the consumer for each element of the linked list, but can abort.
   188  func (q *LinkedList[T]) ReverseEachUntil(consumer func(value T) bool) {
   189  	if q.head == nil {
   190  		return
   191  	}
   192  
   193  	nodePtr := q.tail
   194  	for nodePtr != nil {
   195  		if !consumer(nodePtr.Value) {
   196  			return
   197  		}
   198  		nodePtr = nodePtr.Next
   199  	}
   200  }
   201  
   202  // Contents returns the full contents of the queue as a slice.
   203  func (q *LinkedList[T]) Contents() []T {
   204  	if q.head == nil {
   205  		return nil
   206  	}
   207  
   208  	var values []T
   209  	nodePtr := q.head
   210  	for nodePtr != nil {
   211  		values = append(values, nodePtr.Value)
   212  		nodePtr = nodePtr.Previous
   213  	}
   214  	return values
   215  }
   216  
   217  type listNode[T any] struct {
   218  	Next     *listNode[T]
   219  	Previous *listNode[T]
   220  	Value    T
   221  }