github.com/go-playground/pkg/v5@v5.29.1/container/list/doubly_linked.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  package listext
     5  
     6  // Node is an element of the doubly linked list.
     7  type Node[V any] struct {
     8  	next, prev *Node[V]
     9  	Value      V
    10  }
    11  
    12  // Next returns the nodes next Value or nil if it is at the tail.
    13  func (n *Node[V]) Next() *Node[V] {
    14  	return n.next
    15  }
    16  
    17  // Prev returns the nodes previous Value or nil if it is at the head.
    18  func (n *Node[V]) Prev() *Node[V] {
    19  	return n.prev
    20  }
    21  
    22  // DoublyLinkedList is a doubly linked list
    23  type DoublyLinkedList[V any] struct {
    24  	head, tail *Node[V]
    25  	len        int
    26  }
    27  
    28  // NewDoublyLinked creates a DoublyLinkedList for use.
    29  func NewDoublyLinked[V any]() *DoublyLinkedList[V] {
    30  	return new(DoublyLinkedList[V])
    31  }
    32  
    33  // PushFront adds an element first in the list.
    34  func (d *DoublyLinkedList[V]) PushFront(v V) *Node[V] {
    35  	node := &Node[V]{
    36  		Value: v,
    37  	}
    38  	d.pushFront(node)
    39  	return d.head
    40  }
    41  
    42  func (d *DoublyLinkedList[V]) pushFront(node *Node[V]) {
    43  	node.next = d.head
    44  	node.prev = nil
    45  
    46  	if d.head == nil {
    47  		d.tail = node
    48  	} else {
    49  		d.head.prev = node
    50  	}
    51  	d.head = node
    52  	d.len++
    53  }
    54  
    55  // PopFront removes the first element and returns it or nil.
    56  func (d *DoublyLinkedList[V]) PopFront() *Node[V] {
    57  	if d.IsEmpty() {
    58  		return nil
    59  	}
    60  
    61  	node := d.head
    62  	d.head = node.next
    63  	if d.head == nil {
    64  		d.tail = nil
    65  	} else {
    66  		d.head.prev = nil
    67  	}
    68  	d.len--
    69  	// ensure no leakage
    70  	node.next, node.prev = nil, nil
    71  	return node
    72  }
    73  
    74  // PushBack appends an element to the back of a list.
    75  func (d *DoublyLinkedList[V]) PushBack(v V) *Node[V] {
    76  	node := &Node[V]{
    77  		Value: v,
    78  	}
    79  	d.pushBack(node)
    80  	return d.tail
    81  }
    82  
    83  func (d *DoublyLinkedList[V]) pushBack(node *Node[V]) {
    84  	node.prev = d.tail
    85  	node.next = nil
    86  
    87  	if d.tail == nil {
    88  		d.head = node
    89  	} else {
    90  		d.tail.next = node
    91  	}
    92  	d.tail = node
    93  	d.len++
    94  }
    95  
    96  // PushAfter pushes the supplied Value after the supplied node.
    97  //
    98  // The supplied node must be attached to the current list otherwise undefined behaviour could occur.
    99  func (d *DoublyLinkedList[V]) PushAfter(node *Node[V], v V) *Node[V] {
   100  	newNode := &Node[V]{
   101  		Value: v,
   102  	}
   103  	d.moveAfter(node, newNode)
   104  	return newNode
   105  }
   106  
   107  // MoveAfter moves the `moving` node after the supplied `node`.
   108  //
   109  // The supplied `node` and `moving` nodes must be attached to the current list otherwise
   110  // undefined behaviour could occur.
   111  func (d *DoublyLinkedList[V]) MoveAfter(node *Node[V], moving *Node[V]) {
   112  	// first detach node were moving after, in case it was already attached somewhere else in the list.
   113  	d.Remove(moving)
   114  	d.moveAfter(node, moving)
   115  }
   116  
   117  func (d *DoublyLinkedList[V]) moveAfter(node *Node[V], moving *Node[V]) {
   118  	next := node.next
   119  
   120  	// no next means node == d.tail
   121  	if next == nil {
   122  		d.pushBack(moving)
   123  	} else {
   124  		node.next = moving
   125  		moving.prev = node
   126  		moving.next = next
   127  		next.prev = moving
   128  		d.len++
   129  	}
   130  }
   131  
   132  // PushBefore pushes the supplied Value before the supplied node.
   133  //
   134  // The supplied node must be attached to the current list otherwise undefined behaviour could occur.
   135  func (d *DoublyLinkedList[V]) PushBefore(node *Node[V], v V) *Node[V] {
   136  	newNode := &Node[V]{
   137  		Value: v,
   138  	}
   139  	d.moveBefore(node, newNode)
   140  	return newNode
   141  }
   142  
   143  // InsertBefore inserts the supplied node before the supplied node.
   144  //
   145  // The supplied node must be attached to the current list otherwise undefined behaviour could occur.
   146  func (d *DoublyLinkedList[V]) InsertBefore(node *Node[V], inserting *Node[V]) {
   147  	d.moveBefore(node, inserting)
   148  }
   149  
   150  // InsertAfter inserts the supplied node after the supplied node.
   151  //
   152  // The supplied node must be attached to the current list otherwise undefined behaviour could occur.
   153  func (d *DoublyLinkedList[V]) InsertAfter(node *Node[V], inserting *Node[V]) {
   154  	d.moveAfter(node, inserting)
   155  }
   156  
   157  // MoveBefore moves the `moving` node before the supplied `node`.
   158  //
   159  // The supplied `node` and `moving` nodes must be attached to the current list otherwise
   160  // undefined behaviour could occur.
   161  func (d *DoublyLinkedList[V]) MoveBefore(node *Node[V], moving *Node[V]) {
   162  	// first detach node were moving after, in case it was already attached somewhere else in the list.
   163  	d.Remove(moving)
   164  	d.moveBefore(node, moving)
   165  }
   166  
   167  func (d *DoublyLinkedList[V]) moveBefore(node *Node[V], moving *Node[V]) {
   168  	prev := node.prev
   169  
   170  	// no prev means node == d.head
   171  	if prev == nil {
   172  		d.pushFront(moving)
   173  	} else {
   174  		node.prev = moving
   175  		moving.next = node
   176  		moving.prev = prev
   177  		prev.next = moving
   178  		d.len++
   179  	}
   180  }
   181  
   182  // PopBack removes the last element from a list and returns it or nil.
   183  func (d *DoublyLinkedList[V]) PopBack() *Node[V] {
   184  	if d.IsEmpty() {
   185  		return nil
   186  	}
   187  
   188  	node := d.tail
   189  	d.tail = node.prev
   190  
   191  	if d.tail == nil {
   192  		d.head = nil
   193  	} else {
   194  		d.tail.next = nil
   195  	}
   196  	d.len--
   197  	// ensure no leakage
   198  	node.next, node.prev = nil, nil
   199  	return node
   200  }
   201  
   202  // Front returns the front/head element for use without removing it or nil list is empty.
   203  func (d *DoublyLinkedList[V]) Front() *Node[V] {
   204  	return d.head
   205  }
   206  
   207  // Back returns the end/tail element for use without removing it or nil list is empty.
   208  func (d *DoublyLinkedList[V]) Back() *Node[V] {
   209  	return d.tail
   210  }
   211  
   212  // Remove removes the provided element from the Linked List.
   213  //
   214  // The supplied node must be attached to the current list otherwise undefined behaviour could occur.
   215  func (d *DoublyLinkedList[V]) Remove(node *Node[V]) {
   216  	if node.prev == nil {
   217  		// is head node
   218  		_ = d.PopFront()
   219  	} else if node.next == nil {
   220  		// is tail node
   221  		_ = d.PopBack()
   222  	} else {
   223  		// is both head and tail nodes, must remap
   224  		node.next.prev = node.prev
   225  		node.prev.next = node.next
   226  		// ensure no leakage
   227  		node.next, node.prev = nil, nil
   228  		d.len--
   229  	}
   230  }
   231  
   232  // MoveToFront moves the provided node to the front/head.
   233  //
   234  // The supplied node must be attached to the current list otherwise undefined behaviour could occur.
   235  func (d *DoublyLinkedList[V]) MoveToFront(node *Node[V]) {
   236  	d.Remove(node)
   237  	d.pushFront(node)
   238  }
   239  
   240  // InsertAtFront pushes the provided node to the front/head.
   241  //
   242  // The supplied node must not be attached to any list otherwise undefined behaviour could occur.
   243  func (d *DoublyLinkedList[V]) InsertAtFront(node *Node[V]) {
   244  	d.pushFront(node)
   245  }
   246  
   247  // MoveToBack moves the provided node to the end/tail.
   248  //
   249  // The supplied node must be attached to the current list otherwise undefined behaviour could occur.
   250  func (d *DoublyLinkedList[V]) MoveToBack(node *Node[V]) {
   251  	d.Remove(node)
   252  	d.pushBack(node)
   253  }
   254  
   255  // InsertAtBack pushes the provided node to the back/tail.
   256  //
   257  // The supplied node must not be attached to any list otherwise undefined behaviour could occur.
   258  func (d *DoublyLinkedList[V]) InsertAtBack(node *Node[V]) {
   259  	d.pushBack(node)
   260  }
   261  
   262  // IsEmpty returns true if the list is empty.
   263  func (d *DoublyLinkedList[V]) IsEmpty() bool {
   264  	return d.len == 0
   265  }
   266  
   267  // Len returns length of the Linked List.
   268  func (d *DoublyLinkedList[V]) Len() int {
   269  	return d.len
   270  }
   271  
   272  // Clear removes all elements from the Linked List.
   273  func (d *DoublyLinkedList[V]) Clear() {
   274  	// must loop and clean up references to each other.
   275  	for {
   276  		if d.PopBack() == nil {
   277  			break
   278  		}
   279  	}
   280  	d.head, d.tail, d.len = nil, nil, 0
   281  }