GoToSocial/vendor/codeberg.org/gruf/go-maps/list.go

155 lines
2.6 KiB
Go

package maps
// list is a doubly-linked list containing elemnts with key-value pairs of given generic parameter types.
type list[K comparable, V any] struct {
head *elem[K, V]
tail *elem[K, V]
len int
}
// Index returns the element at index from list.
func (l *list[K, V]) Index(idx int) *elem[K, V] {
switch {
// Idx in first half
case idx < l.len/2:
elem := l.head
for i := 0; i < idx; i++ {
elem = elem.next
}
return elem
// Index in last half
default:
elem := l.tail
for i := l.len - 1; i > idx; i-- {
elem = elem.prev
}
return elem
}
}
// PushFront will push the given element to the front of the list.
func (l *list[K, V]) PushFront(elem *elem[K, V]) {
if l.len == 0 {
// Set new tail + head
l.head = elem
l.tail = elem
// Link elem to itself
elem.next = elem
elem.prev = elem
} else {
oldHead := l.head
// Link to old head
elem.next = oldHead
oldHead.prev = elem
// Link up to tail
elem.prev = l.tail
l.tail.next = elem
// Set new head
l.head = elem
}
// Incr count
l.len++
}
// PushBack will push the given element to the back of the list.
func (l *list[K, V]) PushBack(elem *elem[K, V]) {
if l.len == 0 {
// Set new tail + head
l.head = elem
l.tail = elem
// Link elem to itself
elem.next = elem
elem.prev = elem
} else {
oldTail := l.tail
// Link up to head
elem.next = l.head
l.head.prev = elem
// Link to old tail
elem.prev = oldTail
oldTail.next = elem
// Set new tail
l.tail = elem
}
// Incr count
l.len++
}
// PopTail will pop the current tail of the list, returns nil if empty.
func (l *list[K, V]) PopTail() *elem[K, V] {
if l.len == 0 {
return nil
}
elem := l.tail
l.Unlink(elem)
return elem
}
// Unlink will unlink the given element from the doubly-linked list chain.
func (l *list[K, V]) Unlink(elem *elem[K, V]) {
if l.len <= 1 {
// Drop elem's links
elem.next = nil
elem.prev = nil
// Only elem in list
l.head = nil
l.tail = nil
l.len = 0
return
}
// Get surrounding elems
next := elem.next
prev := elem.prev
// Relink chain
next.prev = prev
prev.next = next
switch elem {
// Set new head
case l.head:
l.head = next
// Set new tail
case l.tail:
l.tail = prev
}
// Drop elem's links
elem.next = nil
elem.prev = nil
// Decr count
l.len--
}
// elem represents an element in a doubly-linked list.
type elem[K comparable, V any] struct {
next *elem[K, V]
prev *elem[K, V]
K K
V V
}
// allocElems will allocate a slice of empty elements of length.
func allocElems[K comparable, V any](i int) []*elem[K, V] {
s := make([]*elem[K, V], i)
for i := range s {
s[i] = &elem[K, V]{}
}
return s
}