You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
2.1 KiB
86 lines
2.1 KiB
package slog
|
|
|
|
// A list[T] is an immutable sequence.
|
|
// It supports three operations: append, len and indexing (at).
|
|
// The zero value is an empty list.
|
|
//
|
|
// Repeated calls to append happen in amortized O(1) space and time. (Appending
|
|
// an element allocates one node directly, and the normalize operation always
|
|
// doubles the front slice, so we can charge two slots to each element.)
|
|
//
|
|
// The len method takes constant time.
|
|
//
|
|
// The at method requires a normalized list, and then takes constant time.
|
|
//
|
|
// It is possible to obtain quadratic behavior by alternating append and at:
|
|
// the normalize required by at is called for each appended element, causing
|
|
// front to be copied each time.
|
|
type list[T any] struct {
|
|
front []T
|
|
back *node[T] // reversed
|
|
lenBack int
|
|
}
|
|
|
|
type node[T any] struct {
|
|
el T
|
|
next *node[T]
|
|
}
|
|
|
|
// append returns a new list consisting of the receiver with x appended.
|
|
func (l list[T]) append(x T) list[T] {
|
|
if l.front == nil {
|
|
// Empty list; return one with one element.
|
|
return list[T]{
|
|
front: []T{x},
|
|
back: nil,
|
|
lenBack: 0,
|
|
}
|
|
}
|
|
if l.lenBack == len(l.front) {
|
|
// When there are as many elements in back as in front, grow
|
|
// front and move all of back to it.
|
|
l = l.normalize()
|
|
}
|
|
// Push a new node with the element onto back, which is stored in
|
|
// reverse order.
|
|
return list[T]{
|
|
front: l.front,
|
|
back: &node[T]{el: x, next: l.back},
|
|
lenBack: l.lenBack + 1,
|
|
}
|
|
}
|
|
|
|
// len returns the number of elements in the list.
|
|
func (l list[T]) len() int {
|
|
return len(l.front) + l.lenBack
|
|
}
|
|
|
|
// at returns the ith element of the list.
|
|
// The list must be normalized.
|
|
func (l list[T]) at(i int) T {
|
|
if l.back != nil {
|
|
panic("not normalized")
|
|
}
|
|
return l.front[i]
|
|
}
|
|
|
|
// normalize returns a list whose back is nil and whose front contains all the
|
|
// receiver's elements.
|
|
func (l list[T]) normalize() list[T] {
|
|
if l.back == nil {
|
|
return l
|
|
}
|
|
newFront := make([]T, len(l.front)+l.lenBack)
|
|
copy(newFront, l.front)
|
|
i := len(newFront) - 1
|
|
for b := l.back; b != nil; b = b.next {
|
|
newFront[i] = b.el
|
|
i--
|
|
}
|
|
return list[T]{
|
|
front: newFront,
|
|
back: nil,
|
|
lenBack: 0,
|
|
}
|
|
}
|