github.com/MetalBlockchain/metalgo@v1.11.9/utils/linked/list.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package linked
     5  
     6  // ListElement is an element of a linked list.
     7  type ListElement[T any] struct {
     8  	next, prev *ListElement[T]
     9  	list       *List[T]
    10  	Value      T
    11  }
    12  
    13  // Next returns the next element or nil.
    14  func (e *ListElement[T]) Next() *ListElement[T] {
    15  	if p := e.next; e.list != nil && p != &e.list.sentinel {
    16  		return p
    17  	}
    18  	return nil
    19  }
    20  
    21  // Prev returns the previous element or nil.
    22  func (e *ListElement[T]) Prev() *ListElement[T] {
    23  	if p := e.prev; e.list != nil && p != &e.list.sentinel {
    24  		return p
    25  	}
    26  	return nil
    27  }
    28  
    29  // List implements a doubly linked list with a sentinel node.
    30  //
    31  // See: https://en.wikipedia.org/wiki/Doubly_linked_list
    32  //
    33  // This datastructure is designed to be an almost complete drop-in replacement
    34  // for the standard library's "container/list".
    35  //
    36  // The primary design change is to remove all memory allocations from the list
    37  // definition. This allows these lists to be used in performance critical paths.
    38  // Additionally the zero value is not useful. Lists must be created with the
    39  // NewList method.
    40  type List[T any] struct {
    41  	// sentinel is only used as a placeholder to avoid complex nil checks.
    42  	// sentinel.Value is never used.
    43  	sentinel ListElement[T]
    44  	length   int
    45  }
    46  
    47  // NewList creates a new doubly linked list.
    48  func NewList[T any]() *List[T] {
    49  	l := &List[T]{}
    50  	l.sentinel.next = &l.sentinel
    51  	l.sentinel.prev = &l.sentinel
    52  	l.sentinel.list = l
    53  	return l
    54  }
    55  
    56  // Len returns the number of elements in l.
    57  func (l *List[_]) Len() int {
    58  	return l.length
    59  }
    60  
    61  // Front returns the element at the front of l.
    62  // If l is empty, nil is returned.
    63  func (l *List[T]) Front() *ListElement[T] {
    64  	if l.length == 0 {
    65  		return nil
    66  	}
    67  	return l.sentinel.next
    68  }
    69  
    70  // Back returns the element at the back of l.
    71  // If l is empty, nil is returned.
    72  func (l *List[T]) Back() *ListElement[T] {
    73  	if l.length == 0 {
    74  		return nil
    75  	}
    76  	return l.sentinel.prev
    77  }
    78  
    79  // Remove removes e from l if e is in l.
    80  func (l *List[T]) Remove(e *ListElement[T]) {
    81  	if e.list != l {
    82  		return
    83  	}
    84  
    85  	e.prev.next = e.next
    86  	e.next.prev = e.prev
    87  	e.next = nil
    88  	e.prev = nil
    89  	e.list = nil
    90  	l.length--
    91  }
    92  
    93  // PushFront inserts e at the front of l.
    94  // If e is already in a list, l is not modified.
    95  func (l *List[T]) PushFront(e *ListElement[T]) {
    96  	l.insertAfter(e, &l.sentinel)
    97  }
    98  
    99  // PushBack inserts e at the back of l.
   100  // If e is already in a list, l is not modified.
   101  func (l *List[T]) PushBack(e *ListElement[T]) {
   102  	l.insertAfter(e, l.sentinel.prev)
   103  }
   104  
   105  // InsertBefore inserts e immediately before location.
   106  // If e is already in a list, l is not modified.
   107  // If location is not in l, l is not modified.
   108  func (l *List[T]) InsertBefore(e *ListElement[T], location *ListElement[T]) {
   109  	if location.list == l {
   110  		l.insertAfter(e, location.prev)
   111  	}
   112  }
   113  
   114  // InsertAfter inserts e immediately after location.
   115  // If e is already in a list, l is not modified.
   116  // If location is not in l, l is not modified.
   117  func (l *List[T]) InsertAfter(e *ListElement[T], location *ListElement[T]) {
   118  	if location.list == l {
   119  		l.insertAfter(e, location)
   120  	}
   121  }
   122  
   123  // MoveToFront moves e to the front of l.
   124  // If e is not in l, l is not modified.
   125  func (l *List[T]) MoveToFront(e *ListElement[T]) {
   126  	// If e is already at the front of l, there is nothing to do.
   127  	if e != l.sentinel.next {
   128  		l.moveAfter(e, &l.sentinel)
   129  	}
   130  }
   131  
   132  // MoveToBack moves e to the back of l.
   133  // If e is not in l, l is not modified.
   134  func (l *List[T]) MoveToBack(e *ListElement[T]) {
   135  	l.moveAfter(e, l.sentinel.prev)
   136  }
   137  
   138  // MoveBefore moves e immediately before location.
   139  // If the elements are equal or not in l, the list is not modified.
   140  func (l *List[T]) MoveBefore(e, location *ListElement[T]) {
   141  	// Don't introduce a cycle by moving an element before itself.
   142  	if e != location {
   143  		l.moveAfter(e, location.prev)
   144  	}
   145  }
   146  
   147  // MoveAfter moves e immediately after location.
   148  // If the elements are equal or not in l, the list is not modified.
   149  func (l *List[T]) MoveAfter(e, location *ListElement[T]) {
   150  	l.moveAfter(e, location)
   151  }
   152  
   153  func (l *List[T]) insertAfter(e, location *ListElement[T]) {
   154  	if e.list != nil {
   155  		// Don't insert an element that is already in a list
   156  		return
   157  	}
   158  
   159  	e.prev = location
   160  	e.next = location.next
   161  	e.prev.next = e
   162  	e.next.prev = e
   163  	e.list = l
   164  	l.length++
   165  }
   166  
   167  func (l *List[T]) moveAfter(e, location *ListElement[T]) {
   168  	if e.list != l || location.list != l || e == location {
   169  		// Don't modify an element that is in a different list.
   170  		// Don't introduce a cycle by moving an element after itself.
   171  		return
   172  	}
   173  
   174  	e.prev.next = e.next
   175  	e.next.prev = e.prev
   176  
   177  	e.prev = location
   178  	e.next = location.next
   179  	e.prev.next = e
   180  	e.next.prev = e
   181  }
   182  
   183  // PushFront inserts v into a new element at the front of l.
   184  func PushFront[T any](l *List[T], v T) {
   185  	l.PushFront(&ListElement[T]{
   186  		Value: v,
   187  	})
   188  }
   189  
   190  // PushBack inserts v into a new element at the back of l.
   191  func PushBack[T any](l *List[T], v T) {
   192  	l.PushBack(&ListElement[T]{
   193  		Value: v,
   194  	})
   195  }
   196  
   197  // InsertBefore inserts v into a new element immediately before location.
   198  // If location is not in l, l is not modified.
   199  func InsertBefore[T any](l *List[T], v T, location *ListElement[T]) {
   200  	l.InsertBefore(
   201  		&ListElement[T]{
   202  			Value: v,
   203  		},
   204  		location,
   205  	)
   206  }
   207  
   208  // InsertAfter inserts v into a new element immediately after location.
   209  // If location is not in l, l is not modified.
   210  func InsertAfter[T any](l *List[T], v T, location *ListElement[T]) {
   211  	l.InsertAfter(
   212  		&ListElement[T]{
   213  			Value: v,
   214  		},
   215  		location,
   216  	)
   217  }