mirror of
https://gitee.com/johng/gf
synced 2026-07-02 19:31:07 +08:00
It is wrote with glist.List's and list.List's source codes and improve to support T type. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: hailaz <739476267@qq.com>
722 lines
16 KiB
Go
722 lines
16 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
//
|
|
|
|
package glist
|
|
|
|
import (
|
|
"bytes"
|
|
"container/list"
|
|
|
|
"github.com/gogf/gf/v2/internal/deepcopy"
|
|
"github.com/gogf/gf/v2/internal/json"
|
|
"github.com/gogf/gf/v2/internal/rwmutex"
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
)
|
|
|
|
// TElement is an element of a linked list.
|
|
type TElement[T any] struct {
|
|
// Next and previous pointers in the doubly-linked list of elements.
|
|
// To simplify the implementation, internally a list l is implemented
|
|
// as a ring, such that &l.root is both the next element of the last
|
|
// list element (l.Back()) and the previous element of the first list
|
|
// element (l.Front()).
|
|
next, prev *TElement[T]
|
|
|
|
// The list to which this element belongs.
|
|
list *TList[T]
|
|
|
|
// The value stored with this element.
|
|
Value T
|
|
}
|
|
|
|
// Next returns the next list element or nil.
|
|
func (e *TElement[T]) Next() *TElement[T] {
|
|
if p := e.next; e.list != nil && p != &e.list.root {
|
|
return p
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Prev returns the previous list element or nil.
|
|
func (e *TElement[T]) Prev() *TElement[T] {
|
|
if p := e.prev; e.list != nil && p != &e.list.root {
|
|
return p
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TList is a doubly linked list containing a concurrent-safe/unsafe switch.
|
|
// The switch should be set when its initialization and cannot be changed then.
|
|
|
|
type TList[T any] struct {
|
|
mu rwmutex.RWMutex
|
|
root TElement[T] // sentinel list element, only &root, root.prev, and root.next are used
|
|
len int // current list length excluding (this) sentinel element
|
|
}
|
|
|
|
// NewT creates and returns a new empty doubly linked list.
|
|
func NewT[T any](safe ...bool) *TList[T] {
|
|
l := &TList[T]{
|
|
mu: rwmutex.Create(safe...),
|
|
}
|
|
return l.init()
|
|
}
|
|
|
|
// NewTFrom creates and returns a list from a copy of given slice `array`.
|
|
// The parameter `safe` is used to specify whether using list in concurrent-safety,
|
|
// which is false in default.
|
|
func NewTFrom[T any](array []T, safe ...bool) *TList[T] {
|
|
l := NewT[T](safe...)
|
|
for _, v := range array {
|
|
l.insertValue(v, l.root.prev)
|
|
}
|
|
return l
|
|
}
|
|
|
|
// PushFront inserts a new element `e` with value `v` at the front of list `l` and returns `e`.
|
|
func (l *TList[T]) PushFront(v T) (e *TElement[T]) {
|
|
l.mu.Lock()
|
|
l.lazyInit()
|
|
e = l.insertValue(v, &l.root)
|
|
l.mu.Unlock()
|
|
return
|
|
}
|
|
|
|
// PushBack inserts a new element `e` with value `v` at the back of list `l` and returns `e`.
|
|
func (l *TList[T]) PushBack(v T) (e *TElement[T]) {
|
|
l.mu.Lock()
|
|
l.lazyInit()
|
|
e = l.insertValue(v, l.root.prev)
|
|
l.mu.Unlock()
|
|
return
|
|
}
|
|
|
|
// PushFronts inserts multiple new elements with values `values` at the front of list `l`.
|
|
func (l *TList[T]) PushFronts(values []T) {
|
|
l.mu.Lock()
|
|
l.lazyInit()
|
|
for _, v := range values {
|
|
l.insertValue(v, &l.root)
|
|
}
|
|
l.mu.Unlock()
|
|
}
|
|
|
|
// PushBacks inserts multiple new elements with values `values` at the back of list `l`.
|
|
func (l *TList[T]) PushBacks(values []T) {
|
|
l.mu.Lock()
|
|
l.lazyInit()
|
|
for _, v := range values {
|
|
l.insertValue(v, l.root.prev)
|
|
}
|
|
l.mu.Unlock()
|
|
}
|
|
|
|
// PopBack removes the element from back of `l` and returns the value of the element.
|
|
func (l *TList[T]) PopBack() (value T) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
l.lazyInit()
|
|
if l.len == 0 {
|
|
return
|
|
}
|
|
return l.remove(l.root.prev)
|
|
}
|
|
|
|
// PopFront removes the element from front of `l` and returns the value of the element.
|
|
func (l *TList[T]) PopFront() (value T) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
l.lazyInit()
|
|
if l.len == 0 {
|
|
return
|
|
}
|
|
return l.remove(l.root.next)
|
|
}
|
|
|
|
// PopBacks removes `max` elements from back of `l`
|
|
// and returns values of the removed elements as slice.
|
|
func (l *TList[T]) PopBacks(max int) (values []T) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
l.lazyInit()
|
|
|
|
length := l.len
|
|
if length > 0 {
|
|
if max > 0 && max < length {
|
|
length = max
|
|
}
|
|
values = make([]T, length)
|
|
for i := 0; i < length; i++ {
|
|
values[i] = l.remove(l.root.prev)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// PopFronts removes `max` elements from front of `l`
|
|
// and returns values of the removed elements as slice.
|
|
func (l *TList[T]) PopFronts(max int) (values []T) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
l.lazyInit()
|
|
|
|
length := l.len
|
|
if length > 0 {
|
|
if max > 0 && max < length {
|
|
length = max
|
|
}
|
|
values = make([]T, length)
|
|
for i := 0; i < length; i++ {
|
|
values[i] = l.remove(l.root.next)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// PopBackAll removes all elements from back of `l`
|
|
// and returns values of the removed elements as slice.
|
|
func (l *TList[T]) PopBackAll() []T {
|
|
return l.PopBacks(-1)
|
|
}
|
|
|
|
// PopFrontAll removes all elements from front of `l`
|
|
// and returns values of the removed elements as slice.
|
|
func (l *TList[T]) PopFrontAll() []T {
|
|
return l.PopFronts(-1)
|
|
}
|
|
|
|
// FrontAll copies and returns values of all elements from front of `l` as slice.
|
|
func (l *TList[T]) FrontAll() (values []T) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
l.lazyInit()
|
|
length := l.len
|
|
if length > 0 {
|
|
values = make([]T, length)
|
|
for i, e := 0, l.front(); i < length; i, e = i+1, e.Next() {
|
|
values[i] = e.Value
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// BackAll copies and returns values of all elements from back of `l` as slice.
|
|
func (l *TList[T]) BackAll() (values []T) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
l.lazyInit()
|
|
length := l.len
|
|
if length > 0 {
|
|
values = make([]T, length)
|
|
for i, e := 0, l.back(); i < length; i, e = i+1, e.Prev() {
|
|
values[i] = e.Value
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// FrontValue returns value of the first element of `l` or zero value of T if the list is empty.
|
|
func (l *TList[T]) FrontValue() (value T) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
l.lazyInit()
|
|
if e := l.front(); e != nil {
|
|
value = e.Value
|
|
}
|
|
return
|
|
}
|
|
|
|
// BackValue returns value of the last element of `l` or zero value of T if the list is empty.
|
|
func (l *TList[T]) BackValue() (value T) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
l.lazyInit()
|
|
if e := l.back(); e != nil {
|
|
value = e.Value
|
|
}
|
|
return
|
|
}
|
|
|
|
// Front returns the first element of list `l` or nil if the list is empty.
|
|
func (l *TList[T]) Front() (e *TElement[T]) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
|
|
l.lazyInit()
|
|
|
|
e = l.front()
|
|
return
|
|
}
|
|
|
|
// Back returns the last element of list `l` or nil if the list is empty.
|
|
func (l *TList[T]) Back() (e *TElement[T]) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
l.lazyInit()
|
|
|
|
e = l.back()
|
|
return
|
|
}
|
|
|
|
// Len returns the number of elements of list `l`.
|
|
// The complexity is O(1).
|
|
func (l *TList[T]) Len() (length int) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
|
|
l.lazyInit()
|
|
|
|
length = l.len
|
|
return
|
|
}
|
|
|
|
// Size is alias of Len.
|
|
func (l *TList[T]) Size() int {
|
|
return l.Len()
|
|
}
|
|
|
|
// MoveBefore moves element `e` to its new position before `p`.
|
|
// If `e` or `p` is not an element of `l`, or `e` == `p`, the list is not modified.
|
|
// The element and `p` must not be nil.
|
|
func (l *TList[T]) MoveBefore(e, p *TElement[T]) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
l.lazyInit()
|
|
|
|
if e.list != l || e == p || p.list != l {
|
|
return
|
|
}
|
|
l.move(e, p.prev)
|
|
}
|
|
|
|
// MoveAfter moves element `e` to its new position after `p`.
|
|
// If `e` or `p` is not an element of `l`, or `e` == `p`, the list is not modified.
|
|
// The element and `p` must not be nil.
|
|
func (l *TList[T]) MoveAfter(e, p *TElement[T]) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
l.lazyInit()
|
|
if e.list != l || e == p || p.list != l {
|
|
return
|
|
}
|
|
l.move(e, p)
|
|
}
|
|
|
|
// MoveToFront moves element `e` to the front of list `l`.
|
|
// If `e` is not an element of `l`, the list is not modified.
|
|
// The element must not be nil.
|
|
func (l *TList[T]) MoveToFront(e *TElement[T]) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
l.lazyInit()
|
|
|
|
if e.list != l || l.root.next == e {
|
|
return
|
|
}
|
|
// see comment in List.Remove about initialization of l
|
|
l.move(e, &l.root)
|
|
}
|
|
|
|
// MoveToBack moves element `e` to the back of list `l`.
|
|
// If `e` is not an element of `l`, the list is not modified.
|
|
// The element must not be nil.
|
|
func (l *TList[T]) MoveToBack(e *TElement[T]) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
l.lazyInit()
|
|
|
|
if e.list != l || l.root.prev == e {
|
|
return
|
|
}
|
|
// see comment in List.Remove about initialization of l
|
|
l.move(e, l.root.prev)
|
|
}
|
|
|
|
// PushBackList inserts a copy of an other list at the back of list `l`.
|
|
// The lists `l` and `other` may be the same, but they must not be nil.
|
|
func (l *TList[T]) PushBackList(other *TList[T]) {
|
|
if l != other {
|
|
other.mu.RLock()
|
|
defer other.mu.RUnlock()
|
|
}
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
l.lazyInit()
|
|
|
|
for i, e := other.len, other.front(); i > 0; i, e = i-1, e.Next() {
|
|
l.insertValue(e.Value, l.root.prev)
|
|
}
|
|
}
|
|
|
|
// PushFrontList inserts a copy of an other list at the front of list `l`.
|
|
// The lists `l` and `other` may be the same, but they must not be nil.
|
|
func (l *TList[T]) PushFrontList(other *TList[T]) {
|
|
if l != other {
|
|
other.mu.RLock()
|
|
defer other.mu.RUnlock()
|
|
}
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
l.lazyInit()
|
|
|
|
for i, e := other.len, other.back(); i > 0; i, e = i-1, e.Prev() {
|
|
l.insertValue(e.Value, &l.root)
|
|
}
|
|
}
|
|
|
|
// InsertAfter inserts a new element `e` with value `v` immediately after `p` and returns `e`.
|
|
// If `p` is not an element of `l`, the list is not modified.
|
|
// The `p` must not be nil.
|
|
func (l *TList[T]) InsertAfter(p *TElement[T], v T) (e *TElement[T]) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
l.lazyInit()
|
|
if p.list != l {
|
|
return nil
|
|
}
|
|
e = l.insertValue(v, p)
|
|
return
|
|
}
|
|
|
|
// InsertBefore inserts a new element `e` with value `v` immediately before `p` and returns `e`.
|
|
// If `p` is not an element of `l`, the list is not modified.
|
|
// The `p` must not be nil.
|
|
func (l *TList[T]) InsertBefore(p *TElement[T], v T) (e *TElement[T]) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
l.lazyInit()
|
|
if p.list != l {
|
|
return nil
|
|
}
|
|
e = l.insertValue(v, p.prev)
|
|
return
|
|
}
|
|
|
|
// Remove removes `e` from `l` if `e` is an element of list `l`.
|
|
// It returns the element value e.Value.
|
|
// The element must not be nil.
|
|
func (l *TList[T]) Remove(e *TElement[T]) (value T) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
l.lazyInit()
|
|
return l.remove(e)
|
|
}
|
|
|
|
// Removes removes multiple elements `es` from `l` if `es` are elements of list `l`.
|
|
func (l *TList[T]) Removes(es []*TElement[T]) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
l.lazyInit()
|
|
for _, e := range es {
|
|
l.remove(e)
|
|
}
|
|
}
|
|
|
|
// RemoveAll removes all elements from list `l`.
|
|
func (l *TList[T]) RemoveAll() {
|
|
l.mu.Lock()
|
|
l.init()
|
|
l.mu.Unlock()
|
|
}
|
|
|
|
// Clear is alias of RemoveAll.
|
|
func (l *TList[T]) Clear() {
|
|
l.RemoveAll()
|
|
}
|
|
|
|
// ToList converts TList[T] to list.List
|
|
func (l *TList[T]) ToList() *list.List {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
|
|
return l.toList()
|
|
}
|
|
|
|
// toList converts TList[T] to list.List
|
|
func (l *TList[T]) toList() *list.List {
|
|
l.lazyInit()
|
|
|
|
nl := list.New()
|
|
|
|
for e := l.front(); e != nil; e = e.Next() {
|
|
nl.PushBack(e.Value)
|
|
}
|
|
return nl
|
|
}
|
|
|
|
// AppendList append list.List to the end
|
|
func (l *TList[T]) AppendList(nl *list.List) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
l.appendList(nl)
|
|
}
|
|
|
|
// appendList append list.List to the end
|
|
func (l *TList[T]) appendList(nl *list.List) {
|
|
if nl.Len() == 0 {
|
|
return
|
|
}
|
|
|
|
l.lazyInit()
|
|
|
|
for e := nl.Front(); e != nil; e = e.Next() {
|
|
if v, ok := e.Value.(T); ok {
|
|
l.insertValue(v, l.root.prev)
|
|
}
|
|
}
|
|
}
|
|
|
|
// AssignList assigns list.List to now TList[T].
|
|
// It will clear TList[T] first, and append the list.List.
|
|
// Note: Elements in nl that are not assignable to T are silently skipped.
|
|
// Returns the number of skipped (incompatible) elements.
|
|
func (l *TList[T]) AssignList(nl *list.List) int {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
return l.assignList(nl)
|
|
}
|
|
|
|
// assignList assigns list.List to now TList[T].
|
|
// It will clear TList[T] first, and append the list.List.
|
|
// Returns the number of skipped (incompatible) elements.
|
|
func (l *TList[T]) assignList(nl *list.List) int {
|
|
l.init()
|
|
if nl.Len() == 0 {
|
|
return 0
|
|
}
|
|
skipped := 0
|
|
for e := nl.Front(); e != nil; e = e.Next() {
|
|
if v, ok := e.Value.(T); ok {
|
|
l.insertValue(v, l.root.prev)
|
|
} else {
|
|
skipped++
|
|
}
|
|
}
|
|
return skipped
|
|
}
|
|
|
|
// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
|
|
func (l *TList[T]) RLockFunc(f func(list *list.List)) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
|
|
f(l.toList())
|
|
}
|
|
|
|
// LockFunc locks writing with given callback function `f` within RWMutex.Lock.
|
|
func (l *TList[T]) LockFunc(f func(list *list.List)) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
nl := l.toList()
|
|
f(nl)
|
|
l.assignList(nl)
|
|
}
|
|
|
|
// Iterator is alias of IteratorAsc.
|
|
func (l *TList[T]) Iterator(f func(e *TElement[T]) bool) {
|
|
l.IteratorAsc(f)
|
|
}
|
|
|
|
// IteratorAsc iterates the list readonly in ascending order with given callback function `f`.
|
|
// If `f` returns true, then it continues iterating; or false to stop.
|
|
func (l *TList[T]) IteratorAsc(f func(e *TElement[T]) bool) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
l.lazyInit()
|
|
length := l.len
|
|
if length > 0 {
|
|
for i, e := 0, l.front(); i < length; i, e = i+1, e.Next() {
|
|
if !f(e) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// IteratorDesc iterates the list readonly in descending order with given callback function `f`.
|
|
// If `f` returns true, then it continues iterating; or false to stop.
|
|
func (l *TList[T]) IteratorDesc(f func(e *TElement[T]) bool) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
l.lazyInit()
|
|
length := l.len
|
|
if length > 0 {
|
|
for i, e := 0, l.back(); i < length; i, e = i+1, e.Prev() {
|
|
if !f(e) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Join joins list elements with a string `glue`.
|
|
func (l *TList[T]) Join(glue string) string {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
l.lazyInit()
|
|
|
|
buffer := bytes.NewBuffer(nil)
|
|
length := l.len
|
|
if length > 0 {
|
|
for i, e := 0, l.front(); i < length; i, e = i+1, e.Next() {
|
|
buffer.WriteString(gconv.String(e.Value))
|
|
if i != length-1 {
|
|
buffer.WriteString(glue)
|
|
}
|
|
}
|
|
}
|
|
return buffer.String()
|
|
}
|
|
|
|
// String returns current list as a string.
|
|
func (l *TList[T]) String() string {
|
|
if l == nil {
|
|
return ""
|
|
}
|
|
return "[" + l.Join(",") + "]"
|
|
}
|
|
|
|
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
|
func (l TList[T]) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(l.FrontAll())
|
|
}
|
|
|
|
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
|
func (l *TList[T]) UnmarshalJSON(b []byte) error {
|
|
var array []T
|
|
if err := json.UnmarshalUseNumber(b, &array); err != nil {
|
|
return err
|
|
}
|
|
l.init()
|
|
l.PushBacks(array)
|
|
return nil
|
|
}
|
|
|
|
// UnmarshalValue is an interface implement which sets any type of value for list.
|
|
func (l *TList[T]) UnmarshalValue(value any) (err error) {
|
|
var array []T
|
|
switch value.(type) {
|
|
case string, []byte:
|
|
err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
|
|
default:
|
|
anyArray := gconv.SliceAny(value)
|
|
if err = gconv.Scan(anyArray, &array); err != nil {
|
|
return
|
|
}
|
|
}
|
|
l.init()
|
|
l.PushBacks(array)
|
|
return err
|
|
}
|
|
|
|
// DeepCopy implements interface for deep copy of current type.
|
|
func (l *TList[T]) DeepCopy() any {
|
|
if l == nil {
|
|
return nil
|
|
}
|
|
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
|
|
l.lazyInit()
|
|
|
|
var (
|
|
length = l.len
|
|
valuesT = make([]T, length)
|
|
)
|
|
if length > 0 {
|
|
for i, e := 0, l.front(); i < length; i, e = i+1, e.Next() {
|
|
valuesT[i] = deepcopy.Copy(e.Value).(T)
|
|
}
|
|
}
|
|
return NewTFrom(valuesT, l.mu.IsSafe())
|
|
}
|
|
|
|
// Init initializes or clears list l.
|
|
func (l *TList[T]) init() *TList[T] {
|
|
l.root.next = &l.root
|
|
l.root.prev = &l.root
|
|
l.len = 0
|
|
return l
|
|
}
|
|
|
|
// lazyInit lazily initializes a zero List value.
|
|
func (l *TList[T]) lazyInit() {
|
|
if l.root.next == nil {
|
|
l.init()
|
|
}
|
|
}
|
|
|
|
// insert inserts e after at, increments l.len, and returns e.
|
|
func (l *TList[T]) insert(e, at *TElement[T]) *TElement[T] {
|
|
e.prev = at
|
|
e.next = at.next
|
|
e.prev.next = e
|
|
e.next.prev = e
|
|
e.list = l
|
|
l.len++
|
|
return e
|
|
}
|
|
|
|
// insertValue is a convenience wrapper for insert(&Element{Value: v}, at).
|
|
func (l *TList[T]) insertValue(v T, at *TElement[T]) *TElement[T] {
|
|
return l.insert(&TElement[T]{Value: v}, at)
|
|
}
|
|
|
|
// remove removes e from its list, decrements l.len
|
|
func (l *TList[T]) remove(e *TElement[T]) (val T) {
|
|
if e.list != l {
|
|
return
|
|
}
|
|
e.prev.next = e.next
|
|
e.next.prev = e.prev
|
|
e.next = nil // avoid memory leaks
|
|
e.prev = nil // avoid memory leaks
|
|
e.list = nil
|
|
l.len--
|
|
|
|
return e.Value
|
|
}
|
|
|
|
// move moves e to next to at.
|
|
func (l *TList[T]) move(e, at *TElement[T]) {
|
|
if e == at {
|
|
return
|
|
}
|
|
e.prev.next = e.next
|
|
e.next.prev = e.prev
|
|
|
|
e.prev = at
|
|
e.next = at.next
|
|
e.prev.next = e
|
|
e.next.prev = e
|
|
}
|
|
|
|
// front returns the first element of list l or nil if the list is empty.
|
|
func (l *TList[T]) front() *TElement[T] {
|
|
if l.len == 0 {
|
|
return nil
|
|
}
|
|
return l.root.next
|
|
}
|
|
|
|
// back returns the last element of list l or nil if the list is empty.
|
|
func (l *TList[T]) back() *TElement[T] {
|
|
if l.len == 0 {
|
|
return nil
|
|
}
|
|
return l.root.prev
|
|
}
|