aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmir Laher <amirlaher@Amirs-Air.fritz.box>2022-05-19 13:24:02 +1200
committerAmir Laher <amirlaher@Amirs-Air.fritz.box>2022-05-19 13:24:02 +1200
commita1d1726e22b438f592d9dddc614f2cff38ee155e (patch)
treea86c97115ae401b9c54521a5dee4dd83fe4d3a39
parentFix MapBuilder docs (diff)
downloadpds-a1d1726e22b438f592d9dddc614f2cff38ee155e.tar.gz
pds-a1d1726e22b438f592d9dddc614f2cff38ee155e.tar.xz
convert lists to use generics
-rw-r--r--go.mod2
-rw-r--r--immutable.go208
-rw-r--r--immutable_test.go76
3 files changed, 147 insertions, 139 deletions
diff --git a/go.mod b/go.mod
index ea97e54..0691b68 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,3 @@
module github.com/benbjohnson/immutable
-go 1.12
+go 1.18
diff --git a/immutable.go b/immutable.go
index c8da568..1ec851e 100644
--- a/immutable.go
+++ b/immutable.go
@@ -54,38 +54,38 @@ import (
// in Go. They can be updated by appending to the end of the list, prepending
// values to the beginning of the list, or updating existing indexes in the
// list.
-type List struct {
- root listNode // root node
- origin int // offset to zero index element
- size int // total number of elements in use
+type List[T comparable] struct {
+ root listNode[T] // root node
+ origin int // offset to zero index element
+ size int // total number of elements in use
}
// NewList returns a new empty instance of List.
-func NewList() *List {
- return &List{
- root: &listLeafNode{},
+func NewList[T comparable]() *List[T] {
+ return &List[T]{
+ root: &listLeafNode[T]{},
}
}
// clone returns a copy of the list.
-func (l *List) clone() *List {
+func (l *List[T]) clone() *List[T] {
other := *l
return &other
}
// Len returns the number of elements in the list.
-func (l *List) Len() int {
+func (l *List[T]) Len() int {
return l.size
}
// cap returns the total number of possible elements for the current depth.
-func (l *List) cap() int {
+func (l *List[T]) cap() int {
return 1 << (l.root.depth() * listNodeBits)
}
// Get returns the value at the given index. Similar to slices, this method will
// panic if index is below zero or is greater than or equal to the list size.
-func (l *List) Get(index int) interface{} {
+func (l *List[T]) Get(index int) T {
if index < 0 || index >= l.size {
panic(fmt.Sprintf("immutable.List.Get: index %d out of bounds", index))
}
@@ -95,11 +95,11 @@ func (l *List) Get(index int) interface{} {
// Set returns a new list with value set at index. Similar to slices, this
// method will panic if index is below zero or if the index is greater than
// or equal to the list size.
-func (l *List) Set(index int, value interface{}) *List {
+func (l *List[T]) Set(index int, value T) *List[T] {
return l.set(index, value, false)
}
-func (l *List) set(index int, value interface{}, mutable bool) *List {
+func (l *List[T]) set(index int, value T, mutable bool) *List[T] {
if index < 0 || index >= l.size {
panic(fmt.Sprintf("immutable.List.Set: index %d out of bounds", index))
}
@@ -112,11 +112,11 @@ func (l *List) set(index int, value interface{}, mutable bool) *List {
}
// Append returns a new list with value added to the end of the list.
-func (l *List) Append(value interface{}) *List {
+func (l *List[T]) Append(value T) *List[T] {
return l.append(value, false)
}
-func (l *List) append(value interface{}, mutable bool) *List {
+func (l *List[T]) append(value T, mutable bool) *List[T] {
other := l
if !mutable {
other = l.clone()
@@ -124,7 +124,7 @@ func (l *List) append(value interface{}, mutable bool) *List {
// Expand list to the right if no slots remain.
if other.size+other.origin >= l.cap() {
- newRoot := &listBranchNode{d: other.root.depth() + 1}
+ newRoot := &listBranchNode[T]{d: other.root.depth() + 1}
newRoot.children[0] = other.root
other.root = newRoot
}
@@ -136,11 +136,11 @@ func (l *List) append(value interface{}, mutable bool) *List {
}
// Prepend returns a new list with value added to the beginning of the list.
-func (l *List) Prepend(value interface{}) *List {
+func (l *List[T]) Prepend(value T) *List[T] {
return l.prepend(value, false)
}
-func (l *List) prepend(value interface{}, mutable bool) *List {
+func (l *List[T]) prepend(value T, mutable bool) *List[T] {
other := l
if !mutable {
other = l.clone()
@@ -148,7 +148,7 @@ func (l *List) prepend(value interface{}, mutable bool) *List {
// Expand list to the left if no slots remain.
if other.origin == 0 {
- newRoot := &listBranchNode{d: other.root.depth() + 1}
+ newRoot := &listBranchNode[T]{d: other.root.depth() + 1}
newRoot.children[listNodeSize-1] = other.root
other.root = newRoot
other.origin += (listNodeSize - 1) << (other.root.depth() * listNodeBits)
@@ -168,11 +168,11 @@ func (l *List) prepend(value interface{}, mutable bool) *List {
//
// Unlike Go slices, references to inaccessible elements will be automatically
// removed so they can be garbage collected.
-func (l *List) Slice(start, end int) *List {
+func (l *List[T]) Slice(start, end int) *List[T] {
return l.slice(start, end, false)
}
-func (l *List) slice(start, end int, mutable bool) *List {
+func (l *List[T]) slice(start, end int, mutable bool) *List[T] {
// Panics similar to Go slices.
if start < 0 || start > l.size {
panic(fmt.Sprintf("immutable.List.Slice: start index %d out of bounds", start))
@@ -207,7 +207,7 @@ func (l *List) slice(start, end int, mutable bool) *List {
// Replace the current root with the single child & update origin offset.
other.origin -= i << (other.root.depth() * listNodeBits)
- other.root = other.root.(*listBranchNode).children[i]
+ other.root = other.root.(*listBranchNode[T]).children[i]
}
// Ensure all references are removed before start & after end.
@@ -218,25 +218,25 @@ func (l *List) slice(start, end int, mutable bool) *List {
}
// Iterator returns a new iterator for this list positioned at the first index.
-func (l *List) Iterator() *ListIterator {
- itr := &ListIterator{list: l}
+func (l *List[T]) Iterator() *ListIterator[T] {
+ itr := &ListIterator[T]{list: l}
itr.First()
return itr
}
// ListBuilder represents an efficient builder for creating new Lists.
-type ListBuilder struct {
- list *List // current state
+type ListBuilder[T comparable] struct {
+ list *List[T] // current state
}
// NewListBuilder returns a new instance of ListBuilder.
-func NewListBuilder() *ListBuilder {
- return &ListBuilder{list: NewList()}
+func NewListBuilder[T comparable]() *ListBuilder[T] {
+ return &ListBuilder[T]{list: NewList[T]()}
}
// List returns the current copy of the list.
// The builder should not be used again after the list after this call.
-func (b *ListBuilder) List() *List {
+func (b *ListBuilder[T]) List() *List[T] {
assert(b.list != nil, "immutable.ListBuilder.List(): duplicate call to fetch list")
list := b.list
b.list = nil
@@ -244,14 +244,14 @@ func (b *ListBuilder) List() *List {
}
// Len returns the number of elements in the underlying list.
-func (b *ListBuilder) Len() int {
+func (b *ListBuilder[T]) Len() int {
assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
return b.list.Len()
}
// Get returns the value at the given index. Similar to slices, this method will
// panic if index is below zero or is greater than or equal to the list size.
-func (b *ListBuilder) Get(index int) interface{} {
+func (b *ListBuilder[T]) Get(index int) T {
assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
return b.list.Get(index)
}
@@ -259,32 +259,32 @@ func (b *ListBuilder) Get(index int) interface{} {
// Set updates the value at the given index. Similar to slices, this method will
// panic if index is below zero or if the index is greater than or equal to the
// list size.
-func (b *ListBuilder) Set(index int, value interface{}) {
+func (b *ListBuilder[T]) Set(index int, value T) {
assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
b.list = b.list.set(index, value, true)
}
// Append adds value to the end of the list.
-func (b *ListBuilder) Append(value interface{}) {
+func (b *ListBuilder[T]) Append(value T) {
assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
b.list = b.list.append(value, true)
}
// Prepend adds value to the beginning of the list.
-func (b *ListBuilder) Prepend(value interface{}) {
+func (b *ListBuilder[T]) Prepend(value T) {
assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
b.list = b.list.prepend(value, true)
}
// Slice updates the list with a sublist of elements between start and end index.
// See List.Slice() for more details.
-func (b *ListBuilder) Slice(start, end int) {
+func (b *ListBuilder[T]) Slice(start, end int) {
assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
b.list = b.list.slice(start, end, true)
}
// Iterator returns a new iterator for the underlying list.
-func (b *ListBuilder) Iterator() *ListIterator {
+func (b *ListBuilder[T]) Iterator() *ListIterator[T] {
assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
return b.list.Iterator()
}
@@ -297,53 +297,53 @@ const (
)
// listNode represents either a branch or leaf node in a List.
-type listNode interface {
+type listNode[T comparable] interface {
depth() uint
- get(index int) interface{}
- set(index int, v interface{}, mutable bool) listNode
+ get(index int) T
+ set(index int, v T, mutable bool) listNode[T]
containsBefore(index int) bool
containsAfter(index int) bool
- deleteBefore(index int, mutable bool) listNode
- deleteAfter(index int, mutable bool) listNode
+ deleteBefore(index int, mutable bool) listNode[T]
+ deleteAfter(index int, mutable bool) listNode[T]
}
// newListNode returns a leaf node for depth zero, otherwise returns a branch node.
-func newListNode(depth uint) listNode {
+func newListNode[T comparable](depth uint) listNode[T] {
if depth == 0 {
- return &listLeafNode{}
+ return &listLeafNode[T]{}
}
- return &listBranchNode{d: depth}
+ return &listBranchNode[T]{d: depth}
}
// listBranchNode represents a branch of a List tree at a given depth.
-type listBranchNode struct {
+type listBranchNode[T comparable] struct {
d uint // depth
- children [listNodeSize]listNode
+ children [listNodeSize]listNode[T]
}
// depth returns the depth of this branch node from the leaf.
-func (n *listBranchNode) depth() uint { return n.d }
+func (n *listBranchNode[T]) depth() uint { return n.d }
// get returns the child node at the segment of the index for this depth.
-func (n *listBranchNode) get(index int) interface{} {
+func (n *listBranchNode[T]) get(index int) T {
idx := (index >> (n.d * listNodeBits)) & listNodeMask
return n.children[idx].get(index)
}
// set recursively updates the value at index for each lower depth from the node.
-func (n *listBranchNode) set(index int, v interface{}, mutable bool) listNode {
+func (n *listBranchNode[T]) set(index int, v T, mutable bool) listNode[T] {
idx := (index >> (n.d * listNodeBits)) & listNodeMask
// Find child for the given value in the branch. Create new if it doesn't exist.
child := n.children[idx]
if child == nil {
- child = newListNode(n.depth() - 1)
+ child = newListNode[T](n.depth() - 1)
}
// Return a copy of this branch with the new child.
- var other *listBranchNode
+ var other *listBranchNode[T]
if mutable {
other = n
} else {
@@ -355,7 +355,7 @@ func (n *listBranchNode) set(index int, v interface{}, mutable bool) listNode {
}
// containsBefore returns true if non-nil values exists between [0,index).
-func (n *listBranchNode) containsBefore(index int) bool {
+func (n *listBranchNode[T]) containsBefore(index int) bool {
idx := (index >> (n.d * listNodeBits)) & listNodeMask
// Quickly check if any direct children exist before this segment of the index.
@@ -373,7 +373,7 @@ func (n *listBranchNode) containsBefore(index int) bool {
}
// containsAfter returns true if non-nil values exists between (index,listNodeSize).
-func (n *listBranchNode) containsAfter(index int) bool {
+func (n *listBranchNode[T]) containsAfter(index int) bool {
idx := (index >> (n.d * listNodeBits)) & listNodeMask
// Quickly check if any direct children exist after this segment of the index.
@@ -391,7 +391,7 @@ func (n *listBranchNode) containsAfter(index int) bool {
}
// deleteBefore returns a new node with all elements before index removed.
-func (n *listBranchNode) deleteBefore(index int, mutable bool) listNode {
+func (n *listBranchNode[T]) deleteBefore(index int, mutable bool) listNode[T] {
// Ignore if no nodes exist before the given index.
if !n.containsBefore(index) {
return n
@@ -400,14 +400,14 @@ func (n *listBranchNode) deleteBefore(index int, mutable bool) listNode {
// Return a copy with any nodes prior to the index removed.
idx := (index >> (n.d * listNodeBits)) & listNodeMask
- var other *listBranchNode
+ var other *listBranchNode[T]
if mutable {
other = n
for i := 0; i < idx; i++ {
n.children[i] = nil
}
} else {
- other = &listBranchNode{d: n.d}
+ other = &listBranchNode[T]{d: n.d}
copy(other.children[idx:][:], n.children[idx:][:])
}
@@ -418,7 +418,7 @@ func (n *listBranchNode) deleteBefore(index int, mutable bool) listNode {
}
// deleteBefore returns a new node with all elements before index removed.
-func (n *listBranchNode) deleteAfter(index int, mutable bool) listNode {
+func (n *listBranchNode[T]) deleteAfter(index int, mutable bool) listNode[T] {
// Ignore if no nodes exist after the given index.
if !n.containsAfter(index) {
return n
@@ -427,14 +427,14 @@ func (n *listBranchNode) deleteAfter(index int, mutable bool) listNode {
// Return a copy with any nodes after the index removed.
idx := (index >> (n.d * listNodeBits)) & listNodeMask
- var other *listBranchNode
+ var other *listBranchNode[T]
if mutable {
other = n
for i := idx + 1; i < len(n.children); i++ {
n.children[i] = nil
}
} else {
- other = &listBranchNode{d: n.d}
+ other = &listBranchNode[T]{d: n.d}
copy(other.children[:idx+1], n.children[:idx+1])
}
@@ -445,22 +445,22 @@ func (n *listBranchNode) deleteAfter(index int, mutable bool) listNode {
}
// listLeafNode represents a leaf node in a List.
-type listLeafNode struct {
- children [listNodeSize]interface{}
+type listLeafNode[T comparable] struct {
+ children [listNodeSize]T
}
// depth always returns 0 for leaf nodes.
-func (n *listLeafNode) depth() uint { return 0 }
+func (n *listLeafNode[T]) depth() uint { return 0 }
// get returns the value at the given index.
-func (n *listLeafNode) get(index int) interface{} {
+func (n *listLeafNode[T]) get(index int) T {
return n.children[index&listNodeMask]
}
// set returns a copy of the node with the value at the index updated to v.
-func (n *listLeafNode) set(index int, v interface{}, mutable bool) listNode {
+func (n *listLeafNode[T]) set(index int, v T, mutable bool) listNode[T] {
idx := index & listNodeMask
- var other *listLeafNode
+ var other *listLeafNode[T]
if mutable {
other = n
} else {
@@ -468,14 +468,17 @@ func (n *listLeafNode) set(index int, v interface{}, mutable bool) listNode {
other = &tmp
}
other.children[idx] = v
- return other
+ var otherLN listNode[T]
+ otherLN = other
+ return otherLN
}
// containsBefore returns true if non-nil values exists between [0,index).
-func (n *listLeafNode) containsBefore(index int) bool {
+func (n *listLeafNode[T]) containsBefore(index int) bool {
idx := index & listNodeMask
+ var empty T
for i := 0; i < idx; i++ {
- if n.children[i] != nil {
+ if n.children[i] != empty {
return true
}
}
@@ -483,10 +486,11 @@ func (n *listLeafNode) containsBefore(index int) bool {
}
// containsAfter returns true if non-nil values exists between (index,listNodeSize).
-func (n *listLeafNode) containsAfter(index int) bool {
+func (n *listLeafNode[T]) containsAfter(index int) bool {
idx := index & listNodeMask
+ var empty T
for i := idx + 1; i < len(n.children); i++ {
- if n.children[i] != nil {
+ if n.children[i] != empty {
return true
}
}
@@ -494,62 +498,64 @@ func (n *listLeafNode) containsAfter(index int) bool {
}
// deleteBefore returns a new node with all elements before index removed.
-func (n *listLeafNode) deleteBefore(index int, mutable bool) listNode {
+func (n *listLeafNode[T]) deleteBefore(index int, mutable bool) listNode[T] {
if !n.containsBefore(index) {
return n
}
idx := index & listNodeMask
- var other *listLeafNode
+ var other *listLeafNode[T]
if mutable {
other = n
+ var empty T
for i := 0; i < idx; i++ {
- other.children[i] = nil
+ other.children[i] = empty
}
} else {
- other = &listLeafNode{}
+ other = &listLeafNode[T]{}
copy(other.children[idx:][:], n.children[idx:][:])
}
return other
}
// deleteBefore returns a new node with all elements before index removed.
-func (n *listLeafNode) deleteAfter(index int, mutable bool) listNode {
+func (n *listLeafNode[T]) deleteAfter(index int, mutable bool) listNode[T] {
if !n.containsAfter(index) {
return n
}
idx := index & listNodeMask
- var other *listLeafNode
+ var other *listLeafNode[T]
if mutable {
other = n
+ var empty T
for i := idx + 1; i < len(n.children); i++ {
- other.children[i] = nil
+ other.children[i] = empty
}
} else {
- other = &listLeafNode{}
+ other = &listLeafNode[T]{}
copy(other.children[:idx+1][:], n.children[:idx+1][:])
}
return other
}
// ListIterator represents an ordered iterator over a list.
-type ListIterator struct {
- list *List // source list
- index int // current index position
+type ListIterator[T comparable] struct {
+ list *List[T] // source list
+ index int // current index position
- stack [32]listIteratorElem // search stack
- depth int // stack depth
+ stack [32]listIteratorElem[T] // search stack
+ depth int // stack depth
}
// Done returns true if no more elements remain in the iterator.
-func (itr *ListIterator) Done() bool {
+func (itr *ListIterator[T]) Done() bool {
return itr.index < 0 || itr.index >= itr.list.Len()
}
// First positions the iterator on the first index.
// If source list is empty then no change is made.
-func (itr *ListIterator) First() {
+func (itr *ListIterator[T]) First() {
if itr.list.Len() != 0 {
itr.Seek(0)
}
@@ -557,7 +563,7 @@ func (itr *ListIterator) First() {
// Last positions the iterator on the last index.
// If source list is empty then no change is made.
-func (itr *ListIterator) Last() {
+func (itr *ListIterator[T]) Last() {
if n := itr.list.Len(); n != 0 {
itr.Seek(n - 1)
}
@@ -566,7 +572,7 @@ func (itr *ListIterator) Last() {
// Seek moves the iterator position to the given index in the list.
// Similar to Go slices, this method will panic if index is below zero or if
// the index is greater than or equal to the list size.
-func (itr *ListIterator) Seek(index int) {
+func (itr *ListIterator[T]) Seek(index int) {
// Panic similar to Go slices.
if index < 0 || index >= itr.list.Len() {
panic(fmt.Sprintf("immutable.ListIterator.Seek: index %d out of bounds", index))
@@ -574,22 +580,23 @@ func (itr *ListIterator) Seek(index int) {
itr.index = index
// Reset to the bottom of the stack at seek to the correct position.
- itr.stack[0] = listIteratorElem{node: itr.list.root}
+ itr.stack[0] = listIteratorElem[T]{node: itr.list.root}
itr.depth = 0
itr.seek(index)
}
// Next returns the current index and its value & moves the iterator forward.
// Returns an index of -1 if the there are no more elements to return.
-func (itr *ListIterator) Next() (index int, value interface{}) {
+func (itr *ListIterator[T]) Next() (index int, value T) {
// Exit immediately if there are no elements remaining.
+ var empty T
if itr.Done() {
- return -1, nil
+ return -1, empty
}
// Retrieve current index & value.
elem := &itr.stack[itr.depth]
- index, value = itr.index, elem.node.(*listLeafNode).children[elem.index]
+ index, value = itr.index, elem.node.(*listLeafNode[T]).children[elem.index]
// Increase index. If index is at the end then return immediately.
itr.index++
@@ -609,15 +616,16 @@ func (itr *ListIterator) Next() (index int, value interface{}) {
// Prev returns the current index and value and moves the iterator backward.
// Returns an index of -1 if the there are no more elements to return.
-func (itr *ListIterator) Prev() (index int, value interface{}) {
+func (itr *ListIterator[T]) Prev() (index int, value T) {
// Exit immediately if there are no elements remaining.
+ var empty T
if itr.Done() {
- return -1, nil
+ return -1, empty
}
// Retrieve current index & value.
elem := &itr.stack[itr.depth]
- index, value = itr.index, elem.node.(*listLeafNode).children[elem.index]
+ index, value = itr.index, elem.node.(*listLeafNode[T]).children[elem.index]
// Decrease index. If index is past the beginning then return immediately.
itr.index--
@@ -637,26 +645,26 @@ func (itr *ListIterator) Prev() (index int, value interface{}) {
// seek positions the stack to the given index from the current depth.
// Elements and indexes below the current depth are assumed to be correct.
-func (itr *ListIterator) seek(index int) {
+func (itr *ListIterator[T]) seek(index int) {
// Iterate over each level until we reach a leaf node.
for {
elem := &itr.stack[itr.depth]
elem.index = ((itr.list.origin + index) >> (elem.node.depth() * listNodeBits)) & listNodeMask
switch node := elem.node.(type) {
- case *listBranchNode:
+ case *listBranchNode[T]:
child := node.children[elem.index]
- itr.stack[itr.depth+1] = listIteratorElem{node: child}
+ itr.stack[itr.depth+1] = listIteratorElem[T]{node: child}
itr.depth++
- case *listLeafNode:
+ case *listLeafNode[T]:
return
}
}
}
// listIteratorElem represents the node and it's child index within the stack.
-type listIteratorElem struct {
- node listNode
+type listIteratorElem[T comparable] struct {
+ node listNode[T]
index int
}
diff --git a/immutable_test.go b/immutable_test.go
index 130904f..0032d07 100644
--- a/immutable_test.go
+++ b/immutable_test.go
@@ -15,13 +15,13 @@ var (
func TestList(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
- if size := NewList().Len(); size != 0 {
+ if size := NewList[string]().Len(); size != 0 {
t.Fatalf("unexpected size: %d", size)
}
})
t.Run("Shallow", func(t *testing.T) {
- list := NewList()
+ list := NewList[string]()
list = list.Append("foo")
if v := list.Get(0); v != "foo" {
t.Fatalf("unexpected value: %v", v)
@@ -40,7 +40,7 @@ func TestList(t *testing.T) {
})
t.Run("Deep", func(t *testing.T) {
- list := NewList()
+ list := NewList[int]()
var array []int
for i := 0; i < 100000; i++ {
list = list.Append(i)
@@ -51,14 +51,14 @@ func TestList(t *testing.T) {
t.Fatalf("List.Len()=%d, exp %d", got, exp)
}
for j := range array {
- if got, exp := list.Get(j).(int), array[j]; got != exp {
+ if got, exp := list.Get(j), array[j]; got != exp {
t.Fatalf("%d. List.Get(%d)=%d, exp %d", len(array), j, got, exp)
}
}
})
t.Run("Set", func(t *testing.T) {
- list := NewList()
+ list := NewList[string]()
list = list.Append("foo")
list = list.Append("bar")
@@ -78,7 +78,7 @@ func TestList(t *testing.T) {
var r string
func() {
defer func() { r = recover().(string) }()
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l.Get(-1)
}()
@@ -91,7 +91,7 @@ func TestList(t *testing.T) {
var r string
func() {
defer func() { r = recover().(string) }()
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l.Get(1)
}()
@@ -104,7 +104,7 @@ func TestList(t *testing.T) {
var r string
func() {
defer func() { r = recover().(string) }()
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l.Set(1, "bar")
}()
@@ -117,7 +117,7 @@ func TestList(t *testing.T) {
var r string
func() {
defer func() { r = recover().(string) }()
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l.Slice(2, 3)
}()
@@ -130,7 +130,7 @@ func TestList(t *testing.T) {
var r string
func() {
defer func() { r = recover().(string) }()
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l.Slice(1, 3)
}()
@@ -143,7 +143,7 @@ func TestList(t *testing.T) {
var r string
func() {
defer func() { r = recover().(string) }()
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l = l.Append("bar")
l.Slice(2, 1)
@@ -154,7 +154,7 @@ func TestList(t *testing.T) {
})
t.Run("SliceBeginning", func(t *testing.T) {
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l = l.Append("bar")
l = l.Slice(1, 2)
@@ -169,7 +169,7 @@ func TestList(t *testing.T) {
var r string
func() {
defer func() { r = recover().(string) }()
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l.Iterator().Seek(-1)
}()
@@ -204,16 +204,16 @@ func TestList(t *testing.T) {
// TList represents a list that operates on a standard Go slice & immutable list.
type TList struct {
- im, prev *List
- builder *ListBuilder
+ im, prev *List[int]
+ builder *ListBuilder[int]
std []int
}
// NewTList returns a new instance of TList.
func NewTList() *TList {
return &TList{
- im: NewList(),
- builder: NewListBuilder(),
+ im: NewList[int](),
+ builder: NewListBuilder[int](),
}
}
@@ -302,7 +302,7 @@ func (l *TList) Validate() error {
return nil
}
-func (l *TList) validateForwardIterator(typ string, itr *ListIterator) error {
+func (l *TList) validateForwardIterator(typ string, itr *ListIterator[int]) error {
for i := range l.std {
if j, v := itr.Next(); i != j || l.std[i] != v {
return fmt.Errorf("ListIterator.Next()=<%v,%v>, expected <%v,%v> [%s]", j, v, i, l.std[i], typ)
@@ -313,13 +313,13 @@ func (l *TList) validateForwardIterator(typ string, itr *ListIterator) error {
return fmt.Errorf("ListIterator.Done()=%v, expected %v [%s]", v, done, typ)
}
}
- if i, v := itr.Next(); i != -1 || v != nil {
+ if i, v := itr.Next(); i != -1 || v != 0 {
return fmt.Errorf("ListIterator.Next()=<%v,%v>, expected DONE [%s]", i, v, typ)
}
return nil
}
-func (l *TList) validateBackwardIterator(typ string, itr *ListIterator) error {
+func (l *TList) validateBackwardIterator(typ string, itr *ListIterator[int]) error {
itr.Last()
for i := len(l.std) - 1; i >= 0; i-- {
if j, v := itr.Prev(); i != j || l.std[i] != v {
@@ -331,7 +331,7 @@ func (l *TList) validateBackwardIterator(typ string, itr *ListIterator) error {
return fmt.Errorf("ListIterator.Done()=%v, expected %v [%s]", v, done, typ)
}
}
- if i, v := itr.Prev(); i != -1 || v != nil {
+ if i, v := itr.Prev(); i != -1 || v != 0 {
return fmt.Errorf("ListIterator.Prev()=<%v,%v>, expected DONE [%s]", i, v, typ)
}
return nil
@@ -339,7 +339,7 @@ func (l *TList) validateBackwardIterator(typ string, itr *ListIterator) error {
func BenchmarkList_Append(b *testing.B) {
b.ReportAllocs()
- l := NewList()
+ l := NewList[int]()
for i := 0; i < b.N; i++ {
l = l.Append(i)
}
@@ -347,7 +347,7 @@ func BenchmarkList_Append(b *testing.B) {
func BenchmarkList_Prepend(b *testing.B) {
b.ReportAllocs()
- l := NewList()
+ l := NewList[int]()
for i := 0; i < b.N; i++ {
l = l.Prepend(i)
}
@@ -356,7 +356,7 @@ func BenchmarkList_Prepend(b *testing.B) {
func BenchmarkList_Set(b *testing.B) {
const n = 10000
- l := NewList()
+ l := NewList[int]()
for i := 0; i < 10000; i++ {
l = l.Append(i)
}
@@ -370,7 +370,7 @@ func BenchmarkList_Set(b *testing.B) {
func BenchmarkList_Iterator(b *testing.B) {
const n = 10000
- l := NewList()
+ l := NewList[int]()
for i := 0; i < 10000; i++ {
l = l.Append(i)
}
@@ -417,7 +417,7 @@ func BenchmarkBuiltinSlice_Append(b *testing.B) {
func BenchmarkListBuilder_Append(b *testing.B) {
b.ReportAllocs()
- builder := NewListBuilder()
+ builder := NewListBuilder[int]()
for i := 0; i < b.N; i++ {
builder.Append(i)
}
@@ -425,7 +425,7 @@ func BenchmarkListBuilder_Append(b *testing.B) {
func BenchmarkListBuilder_Prepend(b *testing.B) {
b.ReportAllocs()
- builder := NewListBuilder()
+ builder := NewListBuilder[int]()
for i := 0; i < b.N; i++ {
builder.Prepend(i)
}
@@ -434,7 +434,7 @@ func BenchmarkListBuilder_Prepend(b *testing.B) {
func BenchmarkListBuilder_Set(b *testing.B) {
const n = 10000
- builder := NewListBuilder()
+ builder := NewListBuilder[int]()
for i := 0; i < 10000; i++ {
builder.Append(i)
}
@@ -447,7 +447,7 @@ func BenchmarkListBuilder_Set(b *testing.B) {
}
func ExampleList_Append() {
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l = l.Append("bar")
l = l.Append("baz")
@@ -462,7 +462,7 @@ func ExampleList_Append() {
}
func ExampleList_Prepend() {
- l := NewList()
+ l := NewList[string]()
l = l.Prepend("foo")
l = l.Prepend("bar")
l = l.Prepend("baz")
@@ -477,7 +477,7 @@ func ExampleList_Prepend() {
}
func ExampleList_Set() {
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l = l.Append("bar")
l = l.Set(1, "baz")
@@ -490,7 +490,7 @@ func ExampleList_Set() {
}
func ExampleList_Slice() {
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l = l.Append("bar")
l = l.Append("baz")
@@ -504,7 +504,7 @@ func ExampleList_Slice() {
}
func ExampleList_Iterator() {
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l = l.Append("bar")
l = l.Append("baz")
@@ -521,7 +521,7 @@ func ExampleList_Iterator() {
}
func ExampleList_Iterator_reverse() {
- l := NewList()
+ l := NewList[string]()
l = l.Append("foo")
l = l.Append("bar")
l = l.Append("baz")
@@ -539,7 +539,7 @@ func ExampleList_Iterator_reverse() {
}
func ExampleListBuilder_Append() {
- b := NewListBuilder()
+ b := NewListBuilder[string]()
b.Append("foo")
b.Append("bar")
b.Append("baz")
@@ -555,7 +555,7 @@ func ExampleListBuilder_Append() {
}
func ExampleListBuilder_Prepend() {
- b := NewListBuilder()
+ b := NewListBuilder[string]()
b.Prepend("foo")
b.Prepend("bar")
b.Prepend("baz")
@@ -571,7 +571,7 @@ func ExampleListBuilder_Prepend() {
}
func ExampleListBuilder_Set() {
- b := NewListBuilder()
+ b := NewListBuilder[string]()
b.Append("foo")
b.Append("bar")
b.Set(1, "baz")
@@ -585,7 +585,7 @@ func ExampleListBuilder_Set() {
}
func ExampleListBuilder_Slice() {
- b := NewListBuilder()
+ b := NewListBuilder[string]()
b.Append("foo")
b.Append("bar")
b.Append("baz")