mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
218 lines
5.4 KiB
Go
218 lines
5.4 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package linked
|
|
|
|
// ListElement is an element of a linked list.
|
|
type ListElement[T any] struct {
|
|
next, prev *ListElement[T]
|
|
list *List[T]
|
|
Value T
|
|
}
|
|
|
|
// Next returns the next element or nil.
|
|
func (e *ListElement[T]) Next() *ListElement[T] {
|
|
if p := e.next; e.list != nil && p != &e.list.sentinel {
|
|
return p
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Prev returns the previous element or nil.
|
|
func (e *ListElement[T]) Prev() *ListElement[T] {
|
|
if p := e.prev; e.list != nil && p != &e.list.sentinel {
|
|
return p
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// List implements a doubly linked list with a sentinel node.
|
|
//
|
|
// See: https://en.wikipedia.org/wiki/Doubly_linked_list
|
|
//
|
|
// This datastructure is designed to be an almost complete drop-in replacement
|
|
// for the standard library's "container/list".
|
|
//
|
|
// The primary design change is to remove all memory allocations from the list
|
|
// definition. This allows these lists to be used in performance critical paths.
|
|
// Additionally the zero value is not useful. Lists must be created with the
|
|
// NewList method.
|
|
type List[T any] struct {
|
|
// sentinel is only used as a placeholder to avoid complex nil checks.
|
|
// sentinel.Value is never used.
|
|
sentinel ListElement[T]
|
|
length int
|
|
}
|
|
|
|
// NewList creates a new doubly linked list.
|
|
func NewList[T any]() *List[T] {
|
|
l := &List[T]{}
|
|
l.sentinel.next = &l.sentinel
|
|
l.sentinel.prev = &l.sentinel
|
|
l.sentinel.list = l
|
|
return l
|
|
}
|
|
|
|
// Len returns the number of elements in l.
|
|
func (l *List[_]) Len() int {
|
|
return l.length
|
|
}
|
|
|
|
// Front returns the element at the front of l.
|
|
// If l is empty, nil is returned.
|
|
func (l *List[T]) Front() *ListElement[T] {
|
|
if l.length == 0 {
|
|
return nil
|
|
}
|
|
return l.sentinel.next
|
|
}
|
|
|
|
// Back returns the element at the back of l.
|
|
// If l is empty, nil is returned.
|
|
func (l *List[T]) Back() *ListElement[T] {
|
|
if l.length == 0 {
|
|
return nil
|
|
}
|
|
return l.sentinel.prev
|
|
}
|
|
|
|
// Remove removes e from l if e is in l.
|
|
func (l *List[T]) Remove(e *ListElement[T]) {
|
|
if e.list != l {
|
|
return
|
|
}
|
|
|
|
e.prev.next = e.next
|
|
e.next.prev = e.prev
|
|
e.next = nil
|
|
e.prev = nil
|
|
e.list = nil
|
|
l.length--
|
|
}
|
|
|
|
// PushFront inserts e at the front of l.
|
|
// If e is already in a list, l is not modified.
|
|
func (l *List[T]) PushFront(e *ListElement[T]) {
|
|
l.insertAfter(e, &l.sentinel)
|
|
}
|
|
|
|
// PushBack inserts e at the back of l.
|
|
// If e is already in a list, l is not modified.
|
|
func (l *List[T]) PushBack(e *ListElement[T]) {
|
|
l.insertAfter(e, l.sentinel.prev)
|
|
}
|
|
|
|
// InsertBefore inserts e immediately before location.
|
|
// If e is already in a list, l is not modified.
|
|
// If location is not in l, l is not modified.
|
|
func (l *List[T]) InsertBefore(e *ListElement[T], location *ListElement[T]) {
|
|
if location.list == l {
|
|
l.insertAfter(e, location.prev)
|
|
}
|
|
}
|
|
|
|
// InsertAfter inserts e immediately after location.
|
|
// If e is already in a list, l is not modified.
|
|
// If location is not in l, l is not modified.
|
|
func (l *List[T]) InsertAfter(e *ListElement[T], location *ListElement[T]) {
|
|
if location.list == l {
|
|
l.insertAfter(e, location)
|
|
}
|
|
}
|
|
|
|
// MoveToFront moves e to the front of l.
|
|
// If e is not in l, l is not modified.
|
|
func (l *List[T]) MoveToFront(e *ListElement[T]) {
|
|
// If e is already at the front of l, there is nothing to do.
|
|
if e != l.sentinel.next {
|
|
l.moveAfter(e, &l.sentinel)
|
|
}
|
|
}
|
|
|
|
// MoveToBack moves e to the back of l.
|
|
// If e is not in l, l is not modified.
|
|
func (l *List[T]) MoveToBack(e *ListElement[T]) {
|
|
l.moveAfter(e, l.sentinel.prev)
|
|
}
|
|
|
|
// MoveBefore moves e immediately before location.
|
|
// If the elements are equal or not in l, the list is not modified.
|
|
func (l *List[T]) MoveBefore(e, location *ListElement[T]) {
|
|
// Don't introduce a cycle by moving an element before itself.
|
|
if e != location {
|
|
l.moveAfter(e, location.prev)
|
|
}
|
|
}
|
|
|
|
// MoveAfter moves e immediately after location.
|
|
// If the elements are equal or not in l, the list is not modified.
|
|
func (l *List[T]) MoveAfter(e, location *ListElement[T]) {
|
|
l.moveAfter(e, location)
|
|
}
|
|
|
|
func (l *List[T]) insertAfter(e, location *ListElement[T]) {
|
|
if e.list != nil {
|
|
// Don't insert an element that is already in a list
|
|
return
|
|
}
|
|
|
|
e.prev = location
|
|
e.next = location.next
|
|
e.prev.next = e
|
|
e.next.prev = e
|
|
e.list = l
|
|
l.length++
|
|
}
|
|
|
|
func (l *List[T]) moveAfter(e, location *ListElement[T]) {
|
|
if e.list != l || location.list != l || e == location {
|
|
// Don't modify an element that is in a different list.
|
|
// Don't introduce a cycle by moving an element after itself.
|
|
return
|
|
}
|
|
|
|
e.prev.next = e.next
|
|
e.next.prev = e.prev
|
|
|
|
e.prev = location
|
|
e.next = location.next
|
|
e.prev.next = e
|
|
e.next.prev = e
|
|
}
|
|
|
|
// PushFront inserts v into a new element at the front of l.
|
|
func PushFront[T any](l *List[T], v T) {
|
|
l.PushFront(&ListElement[T]{
|
|
Value: v,
|
|
})
|
|
}
|
|
|
|
// PushBack inserts v into a new element at the back of l.
|
|
func PushBack[T any](l *List[T], v T) {
|
|
l.PushBack(&ListElement[T]{
|
|
Value: v,
|
|
})
|
|
}
|
|
|
|
// InsertBefore inserts v into a new element immediately before location.
|
|
// If location is not in l, l is not modified.
|
|
func InsertBefore[T any](l *List[T], v T, location *ListElement[T]) {
|
|
l.InsertBefore(
|
|
&ListElement[T]{
|
|
Value: v,
|
|
},
|
|
location,
|
|
)
|
|
}
|
|
|
|
// InsertAfter inserts v into a new element immediately after location.
|
|
// If location is not in l, l is not modified.
|
|
func InsertAfter[T any](l *List[T], v T, location *ListElement[T]) {
|
|
l.InsertAfter(
|
|
&ListElement[T]{
|
|
Value: v,
|
|
},
|
|
location,
|
|
)
|
|
}
|