mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-30 07:32:45 +00:00
205 lines
3.6 KiB
Go
205 lines
3.6 KiB
Go
|
package list
|
||
|
|
||
|
// Elem represents an element in a doubly-linked list.
|
||
|
type Elem[T any] struct {
|
||
|
Next *Elem[T]
|
||
|
Prev *Elem[T]
|
||
|
Value T
|
||
|
}
|
||
|
|
||
|
// List implements a doubly-linked list, where:
|
||
|
// - Head = index 0 (i.e. the front)
|
||
|
// - Tail = index n-1 (i.e. the back)
|
||
|
type List[T any] struct {
|
||
|
Head *Elem[T]
|
||
|
Tail *Elem[T]
|
||
|
len int
|
||
|
}
|
||
|
|
||
|
// Len returns the current list length.
|
||
|
func (l *List[T]) Len() int {
|
||
|
return l.len
|
||
|
}
|
||
|
|
||
|
// PushFront adds 'v' to the beginning of the list.
|
||
|
func (l *List[T]) PushFront(v T) *Elem[T] {
|
||
|
elem := &Elem[T]{Value: v}
|
||
|
l.PushElemFront(elem)
|
||
|
return elem
|
||
|
}
|
||
|
|
||
|
// PushBack adds 'v' to the end of the list.
|
||
|
func (l *List[T]) PushBack(v T) *Elem[T] {
|
||
|
elem := &Elem[T]{Value: v}
|
||
|
l.PushElemBack(elem)
|
||
|
return elem
|
||
|
}
|
||
|
|
||
|
// InsertBefore adds 'v' into the list before 'at'.
|
||
|
func (l *List[T]) InsertBefore(v T, at *Elem[T]) *Elem[T] {
|
||
|
elem := &Elem[T]{Value: v}
|
||
|
l.InsertElemBefore(elem, at)
|
||
|
return elem
|
||
|
}
|
||
|
|
||
|
// InsertAfter adds 'v' into the list after 'at'.
|
||
|
func (l *List[T]) InsertAfter(v T, at *Elem[T]) *Elem[T] {
|
||
|
elem := &Elem[T]{Value: v}
|
||
|
l.InsertElemAfter(elem, at)
|
||
|
return elem
|
||
|
}
|
||
|
|
||
|
// PushFrontNode adds 'elem' to the front of the list.
|
||
|
func (l *List[T]) PushElemFront(elem *Elem[T]) {
|
||
|
if elem == l.Head {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set new head.
|
||
|
oldHead := l.Head
|
||
|
l.Head = elem
|
||
|
|
||
|
if oldHead != nil {
|
||
|
// Link to old head
|
||
|
elem.Next = oldHead
|
||
|
oldHead.Prev = elem
|
||
|
} else {
|
||
|
// First in list.
|
||
|
l.Tail = elem
|
||
|
}
|
||
|
|
||
|
// Incr count
|
||
|
l.len++
|
||
|
}
|
||
|
|
||
|
// PushBackNode adds 'elem' to the back of the list.
|
||
|
func (l *List[T]) PushElemBack(elem *Elem[T]) {
|
||
|
if elem == l.Tail {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set new tail.
|
||
|
oldTail := l.Tail
|
||
|
l.Tail = elem
|
||
|
|
||
|
if oldTail != nil {
|
||
|
// Link to old tail
|
||
|
elem.Prev = oldTail
|
||
|
oldTail.Next = elem
|
||
|
} else {
|
||
|
// First in list.
|
||
|
l.Head = elem
|
||
|
}
|
||
|
|
||
|
// Incr count
|
||
|
l.len++
|
||
|
}
|
||
|
|
||
|
// InsertElemAfter adds 'elem' into the list after 'at' (i.e. at.Next = elem).
|
||
|
func (l *List[T]) InsertElemAfter(elem *Elem[T], at *Elem[T]) {
|
||
|
if elem == at {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set new 'next'.
|
||
|
oldNext := at.Next
|
||
|
at.Next = elem
|
||
|
|
||
|
// Link to 'at'.
|
||
|
elem.Prev = at
|
||
|
|
||
|
if oldNext == nil {
|
||
|
// Set new tail
|
||
|
l.Tail = elem
|
||
|
} else {
|
||
|
// Link to 'prev'.
|
||
|
oldNext.Prev = elem
|
||
|
elem.Next = oldNext
|
||
|
}
|
||
|
|
||
|
// Incr count
|
||
|
l.len++
|
||
|
}
|
||
|
|
||
|
// InsertElemBefore adds 'elem' into the list before 'at' (i.e. at.Prev = elem).
|
||
|
func (l *List[T]) InsertElemBefore(elem *Elem[T], at *Elem[T]) {
|
||
|
if elem == at {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set new 'prev'.
|
||
|
oldPrev := at.Prev
|
||
|
at.Prev = elem
|
||
|
|
||
|
// Link to 'at'.
|
||
|
elem.Next = at
|
||
|
|
||
|
if oldPrev == nil {
|
||
|
// Set new head
|
||
|
l.Head = elem
|
||
|
} else {
|
||
|
// Link to 'next'.
|
||
|
oldPrev.Next = elem
|
||
|
elem.Prev = oldPrev
|
||
|
}
|
||
|
|
||
|
// Incr count
|
||
|
l.len++
|
||
|
}
|
||
|
|
||
|
// Remove removes the 'elem' from the list.
|
||
|
func (l *List[T]) Remove(elem *Elem[T]) {
|
||
|
// Get linked elems.
|
||
|
next := elem.Next
|
||
|
prev := elem.Prev
|
||
|
|
||
|
// Unset elem.
|
||
|
elem.Next = nil
|
||
|
elem.Prev = nil
|
||
|
|
||
|
switch {
|
||
|
// elem is ONLY one in list.
|
||
|
case next == nil && prev == nil:
|
||
|
l.Head = nil
|
||
|
l.Tail = nil
|
||
|
|
||
|
// elem is front in list.
|
||
|
case next != nil && prev == nil:
|
||
|
l.Head = next
|
||
|
next.Prev = nil
|
||
|
|
||
|
// elem is last in list.
|
||
|
case prev != nil && next == nil:
|
||
|
l.Tail = prev
|
||
|
prev.Next = nil
|
||
|
|
||
|
// elem in middle of list.
|
||
|
default:
|
||
|
next.Prev = prev
|
||
|
prev.Next = next
|
||
|
}
|
||
|
|
||
|
// Decr count
|
||
|
l.len--
|
||
|
}
|
||
|
|
||
|
// Range calls 'fn' on every element from head forward in list.
|
||
|
func (l *List[T]) Range(fn func(*Elem[T])) {
|
||
|
if fn == nil {
|
||
|
panic("nil function")
|
||
|
}
|
||
|
for elem := l.Head; elem != nil; elem = elem.Next {
|
||
|
fn(elem)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RangeReverse calls 'fn' on every element from tail backward in list.
|
||
|
func (l *List[T]) RangeReverse(fn func(*Elem[T])) {
|
||
|
if fn == nil {
|
||
|
panic("nil function")
|
||
|
}
|
||
|
for elem := l.Tail; elem != nil; elem = elem.Prev {
|
||
|
fn(elem)
|
||
|
}
|
||
|
}
|