aboutsummaryrefslogtreecommitdiff
path: root/immutable_test.go
diff options
context:
space:
mode:
authorBen Johnson <benbjohnson@yahoo.com>2022-10-04 10:02:34 -0600
committerGitHub <noreply@github.com>2022-10-04 10:02:34 -0600
commitd4a6ab5b95141ab730a78aee27d547228dae18ac (patch)
tree10b29fa99b545b8d4e572e75a1d6d5c1bef4d81d /immutable_test.go
parentFix MapBuilder docs (diff)
parentrevert fork-related readme content (diff)
downloadpds-d4a6ab5b95141ab730a78aee27d547228dae18ac.tar.gz
pds-d4a6ab5b95141ab730a78aee27d547228dae18ac.tar.xz
Merge pull request #23 from laher/master
Adds generics
Diffstat (limited to 'immutable_test.go')
-rw-r--r--immutable_test.go458
1 files changed, 207 insertions, 251 deletions
diff --git a/immutable_test.go b/immutable_test.go
index 130904f..c4b0297 100644
--- a/immutable_test.go
+++ b/immutable_test.go
@@ -6,6 +6,8 @@ import (
"math/rand"
"sort"
"testing"
+
+ "golang.org/x/exp/constraints"
)
var (
@@ -15,13 +17,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 +42,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 +53,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 +80,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 +93,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 +106,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 +119,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 +132,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 +145,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 +156,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 +171,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 +206,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 +304,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 +315,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 +333,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 +341,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 +349,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 +358,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 +372,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 +419,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 +427,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 +436,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 +449,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 +464,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 +479,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 +492,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 +506,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 +523,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 +541,7 @@ func ExampleList_Iterator_reverse() {
}
func ExampleListBuilder_Append() {
- b := NewListBuilder()
+ b := NewListBuilder[string]()
b.Append("foo")
b.Append("bar")
b.Append("baz")
@@ -555,7 +557,7 @@ func ExampleListBuilder_Append() {
}
func ExampleListBuilder_Prepend() {
- b := NewListBuilder()
+ b := NewListBuilder[string]()
b.Prepend("foo")
b.Prepend("bar")
b.Prepend("baz")
@@ -571,7 +573,7 @@ func ExampleListBuilder_Prepend() {
}
func ExampleListBuilder_Set() {
- b := NewListBuilder()
+ b := NewListBuilder[string]()
b.Append("foo")
b.Append("bar")
b.Set(1, "baz")
@@ -585,7 +587,7 @@ func ExampleListBuilder_Set() {
}
func ExampleListBuilder_Slice() {
- b := NewListBuilder()
+ b := NewListBuilder[string]()
b.Append("foo")
b.Append("bar")
b.Append("baz")
@@ -602,8 +604,8 @@ func ExampleListBuilder_Slice() {
// Ensure node can support overwrites as it expands.
func TestInternal_mapNode_Overwrite(t *testing.T) {
const n = 1000
- var h intHasher
- var node mapNode = &mapArrayNode{}
+ var h defaultHasher[int]
+ var node mapNode[int, int] = &mapArrayNode[int, int]{}
for i := 0; i < n; i++ {
var resized bool
node = node.set(i, i, 0, h.Hash(i), &h, false, &resized)
@@ -637,11 +639,11 @@ func TestInternal_mapNode_Overwrite(t *testing.T) {
func TestInternal_mapArrayNode(t *testing.T) {
// Ensure 8 or fewer elements stays in an array node.
t.Run("Append", func(t *testing.T) {
- var h intHasher
- n := &mapArrayNode{}
+ var h defaultHasher[int]
+ n := &mapArrayNode[int, int]{}
for i := 0; i < 8; i++ {
var resized bool
- n = n.set(i*10, i, 0, h.Hash(i*10), &h, false, &resized).(*mapArrayNode)
+ n = n.set(i*10, i, 0, h.Hash(i*10), &h, false, &resized).(*mapArrayNode[int, int])
if !resized {
t.Fatal("expected resize")
}
@@ -656,11 +658,11 @@ func TestInternal_mapArrayNode(t *testing.T) {
// Ensure 8 or fewer elements stays in an array node when inserted in reverse.
t.Run("Prepend", func(t *testing.T) {
- var h intHasher
- n := &mapArrayNode{}
+ var h defaultHasher[int]
+ n := &mapArrayNode[int, int]{}
for i := 7; i >= 0; i-- {
var resized bool
- n = n.set(i*10, i, 0, h.Hash(i*10), &h, false, &resized).(*mapArrayNode)
+ n = n.set(i*10, i, 0, h.Hash(i*10), &h, false, &resized).(*mapArrayNode[int, int])
if !resized {
t.Fatal("expected resize")
}
@@ -675,8 +677,8 @@ func TestInternal_mapArrayNode(t *testing.T) {
// Ensure array can transition between node types.
t.Run("Expand", func(t *testing.T) {
- var h intHasher
- var n mapNode = &mapArrayNode{}
+ var h defaultHasher[int]
+ var n mapNode[int, int] = &mapArrayNode[int, int]{}
for i := 0; i < 100; i++ {
var resized bool
n = n.set(i, i, 0, h.Hash(i), &h, false, &resized)
@@ -694,8 +696,8 @@ func TestInternal_mapArrayNode(t *testing.T) {
// Ensure deleting elements returns the correct new node.
RunRandom(t, "Delete", func(t *testing.T, rand *rand.Rand) {
- var h intHasher
- var n mapNode = &mapArrayNode{}
+ var h defaultHasher[int]
+ var n mapNode[int, int] = &mapArrayNode[int, int]{}
for i := 0; i < 8; i++ {
var resized bool
n = n.set(i*10, i, 0, h.Hash(i*10), &h, false, &resized)
@@ -713,7 +715,7 @@ func TestInternal_mapArrayNode(t *testing.T) {
func TestInternal_mapValueNode(t *testing.T) {
t.Run("Simple", func(t *testing.T) {
- var h intHasher
+ var h defaultHasher[int]
n := newMapValueNode(h.Hash(2), 2, 3)
if v, ok := n.get(2, 0, h.Hash(2), &h); !ok {
t.Fatal("expected ok")
@@ -723,10 +725,10 @@ func TestInternal_mapValueNode(t *testing.T) {
})
t.Run("KeyEqual", func(t *testing.T) {
- var h intHasher
+ var h defaultHasher[int]
var resized bool
n := newMapValueNode(h.Hash(2), 2, 3)
- other := n.set(2, 4, 0, h.Hash(2), &h, false, &resized).(*mapValueNode)
+ other := n.set(2, 4, 0, h.Hash(2), &h, false, &resized).(*mapValueNode[int, int])
if other == n {
t.Fatal("expected new node")
} else if got, exp := other.keyHash, h.Hash(2); got != exp {
@@ -741,13 +743,13 @@ func TestInternal_mapValueNode(t *testing.T) {
})
t.Run("KeyHashEqual", func(t *testing.T) {
- h := &mockHasher{
- hash: func(value interface{}) uint32 { return 1 },
- equal: func(a, b interface{}) bool { return a.(int) == b.(int) },
+ h := &mockHasher[int]{
+ hash: func(value int) uint32 { return 1 },
+ equal: func(a, b int) bool { return a == b },
}
var resized bool
n := newMapValueNode(h.Hash(2), 2, 3)
- other := n.set(4, 5, 0, h.Hash(4), h, false, &resized).(*mapHashCollisionNode)
+ other := n.set(4, 5, 0, h.Hash(4), h, false, &resized).(*mapHashCollisionNode[int, int])
if got, exp := other.keyHash, h.Hash(2); got != exp {
t.Fatalf("keyHash=%v, expected %v", got, exp)
} else if got, exp := len(other.entries), 2; got != exp {
@@ -770,10 +772,10 @@ func TestInternal_mapValueNode(t *testing.T) {
t.Run("MergeNode", func(t *testing.T) {
// Inserting into a node with a different index in the mask should split into a bitmap node.
t.Run("NoConflict", func(t *testing.T) {
- var h intHasher
+ var h defaultHasher[int]
var resized bool
n := newMapValueNode(h.Hash(2), 2, 3)
- other := n.set(4, 5, 0, h.Hash(4), &h, false, &resized).(*mapBitmapIndexedNode)
+ other := n.set(4, 5, 0, h.Hash(4), &h, false, &resized).(*mapBitmapIndexedNode[int, int])
if got, exp := other.bitmap, uint32(0x14); got != exp {
t.Fatalf("bitmap=0x%02x, expected 0x%02x", got, exp)
} else if got, exp := len(other.nodes), 2; got != exp {
@@ -781,14 +783,14 @@ func TestInternal_mapValueNode(t *testing.T) {
} else if !resized {
t.Fatal("expected resize")
}
- if node, ok := other.nodes[0].(*mapValueNode); !ok {
+ if node, ok := other.nodes[0].(*mapValueNode[int, int]); !ok {
t.Fatalf("node[0]=%T, unexpected type", other.nodes[0])
} else if got, exp := node.key, 2; got != exp {
t.Fatalf("key[0]=%v, expected %v", got, exp)
} else if got, exp := node.value, 3; got != exp {
t.Fatalf("value[0]=%v, expected %v", got, exp)
}
- if node, ok := other.nodes[1].(*mapValueNode); !ok {
+ if node, ok := other.nodes[1].(*mapValueNode[int, int]); !ok {
t.Fatalf("node[1]=%T, unexpected type", other.nodes[1])
} else if got, exp := node.key, 4; got != exp {
t.Fatalf("key[1]=%v, expected %v", got, exp)
@@ -797,19 +799,19 @@ func TestInternal_mapValueNode(t *testing.T) {
}
// Ensure both values can be read.
- if v, ok := other.get(2, 0, h.Hash(2), &h); !ok || v.(int) != 3 {
+ if v, ok := other.get(2, 0, h.Hash(2), &h); !ok || v != 3 {
t.Fatalf("Get(2)=<%v,%v>", v, ok)
- } else if v, ok := other.get(4, 0, h.Hash(4), &h); !ok || v.(int) != 5 {
+ } else if v, ok := other.get(4, 0, h.Hash(4), &h); !ok || v != 5 {
t.Fatalf("Get(4)=<%v,%v>", v, ok)
}
})
// Reversing the nodes from NoConflict should yield the same result.
t.Run("NoConflictReverse", func(t *testing.T) {
- var h intHasher
+ var h defaultHasher[int]
var resized bool
n := newMapValueNode(h.Hash(4), 4, 5)
- other := n.set(2, 3, 0, h.Hash(2), &h, false, &resized).(*mapBitmapIndexedNode)
+ other := n.set(2, 3, 0, h.Hash(2), &h, false, &resized).(*mapBitmapIndexedNode[int, int])
if got, exp := other.bitmap, uint32(0x14); got != exp {
t.Fatalf("bitmap=0x%02x, expected 0x%02x", got, exp)
} else if got, exp := len(other.nodes), 2; got != exp {
@@ -817,14 +819,14 @@ func TestInternal_mapValueNode(t *testing.T) {
} else if !resized {
t.Fatal("expected resize")
}
- if node, ok := other.nodes[0].(*mapValueNode); !ok {
+ if node, ok := other.nodes[0].(*mapValueNode[int, int]); !ok {
t.Fatalf("node[0]=%T, unexpected type", other.nodes[0])
} else if got, exp := node.key, 2; got != exp {
t.Fatalf("key[0]=%v, expected %v", got, exp)
} else if got, exp := node.value, 3; got != exp {
t.Fatalf("value[0]=%v, expected %v", got, exp)
}
- if node, ok := other.nodes[1].(*mapValueNode); !ok {
+ if node, ok := other.nodes[1].(*mapValueNode[int, int]); !ok {
t.Fatalf("node[1]=%T, unexpected type", other.nodes[1])
} else if got, exp := node.key, 4; got != exp {
t.Fatalf("key[1]=%v, expected %v", got, exp)
@@ -833,22 +835,22 @@ func TestInternal_mapValueNode(t *testing.T) {
}
// Ensure both values can be read.
- if v, ok := other.get(2, 0, h.Hash(2), &h); !ok || v.(int) != 3 {
+ if v, ok := other.get(2, 0, h.Hash(2), &h); !ok || v != 3 {
t.Fatalf("Get(2)=<%v,%v>", v, ok)
- } else if v, ok := other.get(4, 0, h.Hash(4), &h); !ok || v.(int) != 5 {
+ } else if v, ok := other.get(4, 0, h.Hash(4), &h); !ok || v != 5 {
t.Fatalf("Get(4)=<%v,%v>", v, ok)
}
})
// Inserting a node with the same mask index should nest an additional level of bitmap nodes.
t.Run("Conflict", func(t *testing.T) {
- h := &mockHasher{
- hash: func(value interface{}) uint32 { return uint32(value.(int)) << 5 },
- equal: func(a, b interface{}) bool { return a.(int) == b.(int) },
+ h := &mockHasher[int]{
+ hash: func(value int) uint32 { return uint32(value << 5) },
+ equal: func(a, b int) bool { return a == b },
}
var resized bool
n := newMapValueNode(h.Hash(2), 2, 3)
- other := n.set(4, 5, 0, h.Hash(4), h, false, &resized).(*mapBitmapIndexedNode)
+ other := n.set(4, 5, 0, h.Hash(4), h, false, &resized).(*mapBitmapIndexedNode[int, int])
if got, exp := other.bitmap, uint32(0x01); got != exp { // mask is zero, expect first slot.
t.Fatalf("bitmap=0x%02x, expected 0x%02x", got, exp)
} else if got, exp := len(other.nodes), 1; got != exp {
@@ -856,19 +858,19 @@ func TestInternal_mapValueNode(t *testing.T) {
} else if !resized {
t.Fatal("expected resize")
}
- child, ok := other.nodes[0].(*mapBitmapIndexedNode)
+ child, ok := other.nodes[0].(*mapBitmapIndexedNode[int, int])
if !ok {
t.Fatalf("node[0]=%T, unexpected type", other.nodes[0])
}
- if node, ok := child.nodes[0].(*mapValueNode); !ok {
+ if node, ok := child.nodes[0].(*mapValueNode[int, int]); !ok {
t.Fatalf("node[0]=%T, unexpected type", child.nodes[0])
} else if got, exp := node.key, 2; got != exp {
t.Fatalf("key[0]=%v, expected %v", got, exp)
} else if got, exp := node.value, 3; got != exp {
t.Fatalf("value[0]=%v, expected %v", got, exp)
}
- if node, ok := child.nodes[1].(*mapValueNode); !ok {
+ if node, ok := child.nodes[1].(*mapValueNode[int, int]); !ok {
t.Fatalf("node[1]=%T, unexpected type", child.nodes[1])
} else if got, exp := node.key, 4; got != exp {
t.Fatalf("key[1]=%v, expected %v", got, exp)
@@ -877,9 +879,9 @@ func TestInternal_mapValueNode(t *testing.T) {
}
// Ensure both values can be read.
- if v, ok := other.get(2, 0, h.Hash(2), h); !ok || v.(int) != 3 {
+ if v, ok := other.get(2, 0, h.Hash(2), h); !ok || v != 3 {
t.Fatalf("Get(2)=<%v,%v>", v, ok)
- } else if v, ok := other.get(4, 0, h.Hash(4), h); !ok || v.(int) != 5 {
+ } else if v, ok := other.get(4, 0, h.Hash(4), h); !ok || v != 5 {
t.Fatalf("Get(4)=<%v,%v>", v, ok)
} else if v, ok := other.get(10, 0, h.Hash(10), h); ok {
t.Fatalf("Get(10)=<%v,%v>, expected no value", v, ok)
@@ -890,8 +892,8 @@ func TestInternal_mapValueNode(t *testing.T) {
func TestMap_Get(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
- m := NewMap(nil)
- if v, ok := m.Get(100); ok || v != nil {
+ m := NewMap[int, string](nil)
+ if v, ok := m.Get(100); ok {
t.Fatalf("unexpected value: <%v,%v>", v, ok)
}
})
@@ -899,17 +901,17 @@ func TestMap_Get(t *testing.T) {
func TestMap_Set(t *testing.T) {
t.Run("Simple", func(t *testing.T) {
- m := NewMap(nil)
+ m := NewMap[int, string](nil)
itr := m.Iterator()
if !itr.Done() {
t.Fatal("MapIterator.Done()=true, expected false")
- } else if k, v := itr.Next(); k != nil || v != nil {
+ } else if k, v, ok := itr.Next(); ok {
t.Fatalf("MapIterator.Next()=<%v,%v>, expected nil", k, v)
}
})
t.Run("Simple", func(t *testing.T) {
- m := NewMap(nil)
+ m := NewMap[int, string](nil)
m = m.Set(100, "foo")
if v, ok := m.Get(100); !ok || v != "foo" {
t.Fatalf("unexpected value: <%v,%v>", v, ok)
@@ -918,7 +920,7 @@ func TestMap_Set(t *testing.T) {
t.Run("VerySmall", func(t *testing.T) {
const n = 6
- m := NewMap(nil)
+ m := NewMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i+1)
}
@@ -931,7 +933,7 @@ func TestMap_Set(t *testing.T) {
// NOTE: Array nodes store entries in insertion order.
itr := m.Iterator()
for i := 0; i < n; i++ {
- if k, v := itr.Next(); k != i || v != i+1 {
+ if k, v, ok := itr.Next(); !ok || k != i || v != i+1 {
t.Fatalf("MapIterator.Next()=<%v,%v>, exp <%v,%v>", k, v, i, i+1)
}
}
@@ -942,7 +944,7 @@ func TestMap_Set(t *testing.T) {
t.Run("Small", func(t *testing.T) {
const n = 1000
- m := NewMap(nil)
+ m := NewMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i+1)
}
@@ -959,7 +961,7 @@ func TestMap_Set(t *testing.T) {
}
const n = 1000000
- m := NewMap(nil)
+ m := NewMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i+1)
}
@@ -971,7 +973,7 @@ func TestMap_Set(t *testing.T) {
})
t.Run("StringKeys", func(t *testing.T) {
- m := NewMap(nil)
+ m := NewMap[string, string](nil)
m = m.Set("foo", "bar")
m = m.Set("baz", "bat")
m = m.Set("", "EMPTY")
@@ -987,36 +989,6 @@ func TestMap_Set(t *testing.T) {
}
})
- t.Run("ByteSliceKeys", func(t *testing.T) {
- m := NewMap(nil)
- m = m.Set([]byte("foo"), "bar")
- m = m.Set([]byte("baz"), "bat")
- m = m.Set([]byte(""), "EMPTY")
- if v, ok := m.Get([]byte("foo")); !ok || v != "bar" {
- t.Fatalf("unexpected value: <%v,%v>", v, ok)
- } else if v, ok := m.Get([]byte("baz")); !ok || v != "bat" {
- t.Fatalf("unexpected value: <%v,%v>", v, ok)
- } else if v, ok := m.Get([]byte("")); !ok || v != "EMPTY" {
- t.Fatalf("unexpected value: <%v,%v>", v, ok)
- }
- if v, ok := m.Get([]byte("no_such_key")); ok {
- t.Fatalf("expected no value: <%v,%v>", v, ok)
- }
- })
-
- t.Run("NoDefaultHasher", func(t *testing.T) {
- type T struct{}
- var r string
- func() {
- defer func() { r = recover().(string) }()
- m := NewMap(nil)
- m = m.Set(T{}, "bar")
- }()
- if r != `immutable.NewHasher: must set hasher for immutable.T type` {
- t.Fatalf("unexpected panic: %q", r)
- }
- })
-
RunRandom(t, "Random", func(t *testing.T, rand *rand.Rand) {
m := NewTestMap()
for i := 0; i < 10000; i++ {
@@ -1040,7 +1012,7 @@ func TestMap_Overwrite(t *testing.T) {
}
const n = 10000
- m := NewMap(nil)
+ m := NewMap[int, int](nil)
for i := 0; i < n; i++ {
// Set original value.
m = m.Set(i, i)
@@ -1061,7 +1033,7 @@ func TestMap_Overwrite(t *testing.T) {
func TestMap_Delete(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
- m := NewMap(nil)
+ m := NewMap[string, int](nil)
other := m.Delete("foo")
if m != other {
t.Fatal("expected same map")
@@ -1069,7 +1041,7 @@ func TestMap_Delete(t *testing.T) {
})
t.Run("Simple", func(t *testing.T) {
- m := NewMap(nil)
+ m := NewMap[int, string](nil)
m = m.Set(100, "foo")
if v, ok := m.Get(100); !ok || v != "foo" {
t.Fatalf("unexpected value: <%v,%v>", v, ok)
@@ -1078,7 +1050,7 @@ func TestMap_Delete(t *testing.T) {
t.Run("Small", func(t *testing.T) {
const n = 1000
- m := NewMap(nil)
+ m := NewMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i+1)
}
@@ -1095,7 +1067,7 @@ func TestMap_Delete(t *testing.T) {
t.Skip("skipping: short")
}
const n = 1000000
- m := NewMap(nil)
+ m := NewMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i+1)
}
@@ -1142,11 +1114,11 @@ func TestMap_LimitedHash(t *testing.T) {
}
t.Run("Immutable", func(t *testing.T) {
- h := mockHasher{
- hash: func(value interface{}) uint32 { return hashUint64(uint64(value.(int))) % 0xFF },
- equal: func(a, b interface{}) bool { return a.(int) == b.(int) },
+ h := mockHasher[int]{
+ hash: func(value int) uint32 { return hashUint64(uint64(value)) % 0xFF },
+ equal: func(a, b int) bool { return a == b },
}
- m := NewMap(&h)
+ m := NewMap[int, int](&h)
rand := rand.New(rand.NewSource(0))
keys := rand.Perm(100000)
@@ -1170,8 +1142,8 @@ func TestMap_LimitedHash(t *testing.T) {
// Verify iteration.
itr := m.Iterator()
for !itr.Done() {
- if k, v := itr.Next(); v != k.(int)*2 {
- t.Fatalf("MapIterator.Next()=<%v,%v>, expected value %v", k, v, k.(int)*2)
+ if k, v, ok := itr.Next(); !ok || v != k*2 {
+ t.Fatalf("MapIterator.Next()=<%v,%v>, expected value %v", k, v, k*2)
}
}
@@ -1195,11 +1167,11 @@ func TestMap_LimitedHash(t *testing.T) {
})
t.Run("Builder", func(t *testing.T) {
- h := mockHasher{
- hash: func(value interface{}) uint32 { return hashUint64(uint64(value.(int))) % 0xFF },
- equal: func(a, b interface{}) bool { return a.(int) == b.(int) },
+ h := mockHasher[int]{
+ hash: func(value int) uint32 { return hashUint64(uint64(value)) },
+ equal: func(a, b int) bool { return a == b },
}
- b := NewMapBuilder(&h)
+ b := NewMapBuilder[int, int](&h)
rand := rand.New(rand.NewSource(0))
keys := rand.Perm(100000)
@@ -1223,8 +1195,8 @@ func TestMap_LimitedHash(t *testing.T) {
// Verify iteration.
itr := b.Iterator()
for !itr.Done() {
- if k, v := itr.Next(); v != k.(int)*2 {
- t.Fatalf("MapIterator.Next()=<%v,%v>, expected value %v", k, v, k.(int)*2)
+ if k, v, ok := itr.Next(); !ok || v != k*2 {
+ t.Fatalf("MapIterator.Next()=<%v,%v>, expected value %v", k, v, k*2)
}
}
@@ -1245,16 +1217,16 @@ func TestMap_LimitedHash(t *testing.T) {
// TMap represents a combined immutable and stdlib map.
type TMap struct {
- im, prev *Map
- builder *MapBuilder
+ im, prev *Map[int, int]
+ builder *MapBuilder[int, int]
std map[int]int
keys []int
}
func NewTestMap() *TMap {
return &TMap{
- im: NewMap(nil),
- builder: NewMapBuilder(nil),
+ im: NewMap[int, int](nil),
+ builder: NewMapBuilder[int, int](nil),
std: make(map[int]int),
}
}
@@ -1322,11 +1294,11 @@ func (m *TMap) Validate() error {
return nil
}
-func (m *TMap) validateIterator(itr *MapIterator) error {
+func (m *TMap) validateIterator(itr *MapIterator[int, int]) error {
other := make(map[int]int)
for !itr.Done() {
- k, v := itr.Next()
- other[k.(int)] = v.(int)
+ k, v, _ := itr.Next()
+ other[k] = v
}
if len(other) != len(m.std) {
return fmt.Errorf("map iterator size mismatch: %v!=%v", len(m.std), len(other))
@@ -1336,7 +1308,7 @@ func (m *TMap) validateIterator(itr *MapIterator) error {
return fmt.Errorf("map iterator mismatch: key=%v, %v!=%v", k, v, other[k])
}
}
- if k, v := itr.Next(); k != nil || v != nil {
+ if k, v, ok := itr.Next(); ok {
return fmt.Errorf("map iterator returned key/value after done: <%v/%v>", k, v)
}
return nil
@@ -1367,7 +1339,7 @@ func BenchmarkBuiltinMap_Delete(b *testing.B) {
func BenchmarkMap_Set(b *testing.B) {
b.ReportAllocs()
- m := NewMap(nil)
+ m := NewMap[int, int](nil)
for i := 0; i < b.N; i++ {
m = m.Set(i, i)
}
@@ -1376,7 +1348,7 @@ func BenchmarkMap_Set(b *testing.B) {
func BenchmarkMap_Delete(b *testing.B) {
const n = 10000000
- builder := NewMapBuilder(nil)
+ builder := NewMapBuilder[int, int](nil)
for i := 0; i < n; i++ {
builder.Set(i, i)
}
@@ -1391,7 +1363,7 @@ func BenchmarkMap_Delete(b *testing.B) {
func BenchmarkMap_Iterator(b *testing.B) {
const n = 10000
- m := NewMap(nil)
+ m := NewMap[int, int](nil)
for i := 0; i < 10000; i++ {
m = m.Set(i, i)
}
@@ -1411,7 +1383,7 @@ func BenchmarkMap_Iterator(b *testing.B) {
func BenchmarkMapBuilder_Set(b *testing.B) {
b.ReportAllocs()
- builder := NewMapBuilder(nil)
+ builder := NewMapBuilder[int, int](nil)
for i := 0; i < b.N; i++ {
builder.Set(i, i)
}
@@ -1420,7 +1392,7 @@ func BenchmarkMapBuilder_Set(b *testing.B) {
func BenchmarkMapBuilder_Delete(b *testing.B) {
const n = 10000000
- builder := NewMapBuilder(nil)
+ builder := NewMapBuilder[int, int](nil)
for i := 0; i < n; i++ {
builder.Set(i, i)
}
@@ -1433,7 +1405,7 @@ func BenchmarkMapBuilder_Delete(b *testing.B) {
}
func ExampleMap_Set() {
- m := NewMap(nil)
+ m := NewMap[string, any](nil)
m = m.Set("foo", "bar")
m = m.Set("baz", 100)
@@ -1452,7 +1424,7 @@ func ExampleMap_Set() {
}
func ExampleMap_Delete() {
- m := NewMap(nil)
+ m := NewMap[string, any](nil)
m = m.Set("foo", "bar")
m = m.Set("baz", 100)
m = m.Delete("baz")
@@ -1468,7 +1440,7 @@ func ExampleMap_Delete() {
}
func ExampleMap_Iterator() {
- m := NewMap(nil)
+ m := NewMap[string, int](nil)
m = m.Set("apple", 100)
m = m.Set("grape", 200)
m = m.Set("kiwi", 300)
@@ -1481,7 +1453,7 @@ func ExampleMap_Iterator() {
itr := m.Iterator()
for !itr.Done() {
- k, v := itr.Next()
+ k, v, _ := itr.Next()
fmt.Println(k, v)
}
// Output:
@@ -1497,7 +1469,7 @@ func ExampleMap_Iterator() {
}
func ExampleMapBuilder_Set() {
- b := NewMapBuilder(nil)
+ b := NewMapBuilder[string, any](nil)
b.Set("foo", "bar")
b.Set("baz", 100)
@@ -1517,7 +1489,7 @@ func ExampleMapBuilder_Set() {
}
func ExampleMapBuilder_Delete() {
- b := NewMapBuilder(nil)
+ b := NewMapBuilder[string, any](nil)
b.Set("foo", "bar")
b.Set("baz", 100)
b.Delete("baz")
@@ -1535,12 +1507,12 @@ func ExampleMapBuilder_Delete() {
func TestInternalSortedMapLeafNode(t *testing.T) {
RunRandom(t, "NoSplit", func(t *testing.T, rand *rand.Rand) {
- var cmpr intComparer
- var node sortedMapNode = &sortedMapLeafNode{}
+ var cmpr defaultComparer[int]
+ var node sortedMapNode[int, int] = &sortedMapLeafNode[int, int]{}
var keys []int
for _, i := range rand.Perm(32) {
var resized bool
- var splitNode sortedMapNode
+ var splitNode sortedMapNode[int, int]
node, splitNode = node.set(i, i*10, &cmpr, false, &resized)
if !resized {
t.Fatal("expected resize")
@@ -1570,8 +1542,9 @@ func TestInternalSortedMapLeafNode(t *testing.T) {
})
RunRandom(t, "Overwrite", func(t *testing.T, rand *rand.Rand) {
- var cmpr intComparer
- var node sortedMapNode = &sortedMapLeafNode{}
+ var cmpr defaultComparer[int]
+ var node sortedMapNode[int, int] = &sortedMapLeafNode[int, int]{}
+
for _, i := range rand.Perm(32) {
var resized bool
node, _ = node.set(i, i*2, &cmpr, false, &resized)
@@ -1593,9 +1566,9 @@ func TestInternalSortedMapLeafNode(t *testing.T) {
})
t.Run("Split", func(t *testing.T) {
- // Fill leaf node.
- var cmpr intComparer
- var node sortedMapNode = &sortedMapLeafNode{}
+ // Fill leaf node. var cmpr defaultComparer[int]
+ var cmpr defaultComparer[int]
+ var node sortedMapNode[int, int] = &sortedMapLeafNode[int, int]{}
for i := 0; i < 32; i++ {
var resized bool
node, _ = node.set(i, i*10, &cmpr, false, &resized)
@@ -1606,7 +1579,7 @@ func TestInternalSortedMapLeafNode(t *testing.T) {
newNode, splitNode := node.set(32, 320, &cmpr, false, &resized)
// Verify node contents.
- newLeafNode, ok := newNode.(*sortedMapLeafNode)
+ newLeafNode, ok := newNode.(*sortedMapLeafNode[int, int])
if !ok {
t.Fatalf("unexpected node type: %T", newLeafNode)
} else if n := len(newLeafNode.entries); n != 16 {
@@ -1619,7 +1592,7 @@ func TestInternalSortedMapLeafNode(t *testing.T) {
}
// Verify split node contents.
- splitLeafNode, ok := splitNode.(*sortedMapLeafNode)
+ splitLeafNode, ok := splitNode.(*sortedMapLeafNode[int, int])
if !ok {
t.Fatalf("unexpected split node type: %T", splitLeafNode)
} else if n := len(splitLeafNode.entries); n != 17 {
@@ -1643,17 +1616,17 @@ func TestInternalSortedMapBranchNode(t *testing.T) {
sort.Ints(keys[:2]) // ensure first two keys are sorted for initial insert.
// Initialize branch with two leafs.
- var cmpr intComparer
- leaf0 := &sortedMapLeafNode{entries: []mapEntry{{key: keys[0], value: keys[0] * 10}}}
- leaf1 := &sortedMapLeafNode{entries: []mapEntry{{key: keys[1], value: keys[1] * 10}}}
- var node sortedMapNode = newSortedMapBranchNode(leaf0, leaf1)
+ var cmpr defaultComparer[int]
+ leaf0 := &sortedMapLeafNode[int, int]{entries: []mapEntry[int, int]{{key: keys[0], value: keys[0] * 10}}}
+ leaf1 := &sortedMapLeafNode[int, int]{entries: []mapEntry[int, int]{{key: keys[1], value: keys[1] * 10}}}
+ var node sortedMapNode[int, int] = newSortedMapBranchNode[int, int](leaf0, leaf1)
sort.Ints(keys)
for _, i := range rand.Perm(len(keys)) {
key := keys[i]
var resized bool
- var splitNode sortedMapNode
+ var splitNode sortedMapNode[int, int]
node, splitNode = node.set(key, key*10, &cmpr, false, &resized)
if key == leaf0.entries[0].key || key == leaf1.entries[0].key {
if resized {
@@ -1684,16 +1657,16 @@ func TestInternalSortedMapBranchNode(t *testing.T) {
t.Run("Split", func(t *testing.T) {
// Generate leaf nodes.
- var cmpr intComparer
- children := make([]sortedMapNode, 32)
+ var cmpr defaultComparer[int]
+ children := make([]sortedMapNode[int, int], 32)
for i := range children {
- leaf := &sortedMapLeafNode{entries: make([]mapEntry, 32)}
+ leaf := &sortedMapLeafNode[int, int]{entries: make([]mapEntry[int, int], 32)}
for j := range leaf.entries {
- leaf.entries[j] = mapEntry{key: (i * 32) + j, value: ((i * 32) + j) * 100}
+ leaf.entries[j] = mapEntry[int, int]{key: (i * 32) + j, value: ((i * 32) + j) * 100}
}
children[i] = leaf
}
- var node sortedMapNode = newSortedMapBranchNode(children...)
+ var node sortedMapNode[int, int] = newSortedMapBranchNode(children...)
// Add one more and expect split.
var resized bool
@@ -1701,14 +1674,14 @@ func TestInternalSortedMapBranchNode(t *testing.T) {
// Verify node contents.
var idx int
- newBranchNode, ok := newNode.(*sortedMapBranchNode)
+ newBranchNode, ok := newNode.(*sortedMapBranchNode[int, int])
if !ok {
t.Fatalf("unexpected node type: %T", newBranchNode)
} else if n := len(newBranchNode.elems); n != 16 {
t.Fatalf("unexpected child elems len: %d", n)
}
for i, elem := range newBranchNode.elems {
- child, ok := elem.node.(*sortedMapLeafNode)
+ child, ok := elem.node.(*sortedMapLeafNode[int, int])
if !ok {
t.Fatalf("unexpected child type")
}
@@ -1721,14 +1694,14 @@ func TestInternalSortedMapBranchNode(t *testing.T) {
}
// Verify split node contents.
- splitBranchNode, ok := splitNode.(*sortedMapBranchNode)
+ splitBranchNode, ok := splitNode.(*sortedMapBranchNode[int, int])
if !ok {
t.Fatalf("unexpected split node type: %T", splitBranchNode)
} else if n := len(splitBranchNode.elems); n != 17 {
t.Fatalf("unexpected split node elem len: %d", n)
}
for i, elem := range splitBranchNode.elems {
- child, ok := elem.node.(*sortedMapLeafNode)
+ child, ok := elem.node.(*sortedMapLeafNode[int, int])
if !ok {
t.Fatalf("unexpected split node child type")
}
@@ -1744,8 +1717,8 @@ func TestInternalSortedMapBranchNode(t *testing.T) {
func TestSortedMap_Get(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
- m := NewSortedMap(nil)
- if v, ok := m.Get(100); ok || v != nil {
+ m := NewSortedMap[int, int](nil)
+ if v, ok := m.Get(100); ok {
t.Fatalf("unexpected value: <%v,%v>", v, ok)
}
})
@@ -1753,7 +1726,7 @@ func TestSortedMap_Get(t *testing.T) {
func TestSortedMap_Set(t *testing.T) {
t.Run("Simple", func(t *testing.T) {
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, string](nil)
m = m.Set(100, "foo")
if v, ok := m.Get(100); !ok || v != "foo" {
t.Fatalf("unexpected value: <%v,%v>", v, ok)
@@ -1764,7 +1737,7 @@ func TestSortedMap_Set(t *testing.T) {
t.Run("Small", func(t *testing.T) {
const n = 1000
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i+1)
}
@@ -1781,7 +1754,7 @@ func TestSortedMap_Set(t *testing.T) {
}
const n = 1000000
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i+1)
}
@@ -1793,7 +1766,7 @@ func TestSortedMap_Set(t *testing.T) {
})
t.Run("StringKeys", func(t *testing.T) {
- m := NewSortedMap(nil)
+ m := NewSortedMap[string, string](nil)
m = m.Set("foo", "bar")
m = m.Set("baz", "bat")
m = m.Set("", "EMPTY")
@@ -1809,28 +1782,11 @@ func TestSortedMap_Set(t *testing.T) {
}
})
- t.Run("ByteSliceKeys", func(t *testing.T) {
- m := NewSortedMap(nil)
- m = m.Set([]byte("foo"), "bar")
- m = m.Set([]byte("baz"), "bat")
- m = m.Set([]byte(""), "EMPTY")
- if v, ok := m.Get([]byte("foo")); !ok || v != "bar" {
- t.Fatalf("unexpected value: <%v,%v>", v, ok)
- } else if v, ok := m.Get([]byte("baz")); !ok || v != "bat" {
- t.Fatalf("unexpected value: <%v,%v>", v, ok)
- } else if v, ok := m.Get([]byte("")); !ok || v != "EMPTY" {
- t.Fatalf("unexpected value: <%v,%v>", v, ok)
- }
- if v, ok := m.Get([]byte("no_such_key")); ok {
- t.Fatalf("expected no value: <%v,%v>", v, ok)
- }
- })
-
t.Run("NoDefaultComparer", func(t *testing.T) {
var r string
func() {
defer func() { r = recover().(string) }()
- m := NewSortedMap(nil)
+ m := NewSortedMap[float64, string](nil)
m = m.Set(float64(100), "bar")
}()
if r != `immutable.NewComparer: must set comparer for float64 type` {
@@ -1857,7 +1813,7 @@ func TestSortedMap_Set(t *testing.T) {
// Ensure map can support overwrites as it expands.
func TestSortedMap_Overwrite(t *testing.T) {
const n = 1000
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, int](nil)
for i := 0; i < n; i++ {
// Set original value.
m = m.Set(i, i)
@@ -1878,7 +1834,7 @@ func TestSortedMap_Overwrite(t *testing.T) {
func TestSortedMap_Delete(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, int](nil)
m = m.Delete(100)
if n := m.Len(); n != 0 {
t.Fatalf("SortedMap.Len()=%d, expected 0", n)
@@ -1886,7 +1842,7 @@ func TestSortedMap_Delete(t *testing.T) {
})
t.Run("Simple", func(t *testing.T) {
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, string](nil)
m = m.Set(100, "foo")
if v, ok := m.Get(100); !ok || v != "foo" {
t.Fatalf("unexpected value: <%v,%v>", v, ok)
@@ -1899,7 +1855,7 @@ func TestSortedMap_Delete(t *testing.T) {
t.Run("Small", func(t *testing.T) {
const n = 1000
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i+1)
}
@@ -1925,7 +1881,7 @@ func TestSortedMap_Delete(t *testing.T) {
}
const n = 1000000
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i+1)
}
@@ -1978,25 +1934,25 @@ func TestSortedMap_Delete(t *testing.T) {
func TestSortedMap_Iterator(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
t.Run("First", func(t *testing.T) {
- itr := NewSortedMap(nil).Iterator()
+ itr := NewSortedMap[int, int](nil).Iterator()
itr.First()
- if k, v := itr.Next(); k != nil || v != nil {
+ if k, v, ok := itr.Next(); ok {
t.Fatalf("SortedMapIterator.Next()=<%v,%v>, expected nil", k, v)
}
})
t.Run("Last", func(t *testing.T) {
- itr := NewSortedMap(nil).Iterator()
+ itr := NewSortedMap[int, int](nil).Iterator()
itr.Last()
- if k, v := itr.Prev(); k != nil || v != nil {
+ if k, v, ok := itr.Prev(); ok {
t.Fatalf("SortedMapIterator.Prev()=<%v,%v>, expected nil", k, v)
}
})
t.Run("Seek", func(t *testing.T) {
- itr := NewSortedMap(nil).Iterator()
+ itr := NewSortedMap[string, int](nil).Iterator()
itr.Seek("foo")
- if k, v := itr.Next(); k != nil || v != nil {
+ if k, v, ok := itr.Next(); ok {
t.Fatalf("SortedMapIterator.Next()=<%v,%v>, expected nil", k, v)
}
})
@@ -2004,7 +1960,7 @@ func TestSortedMap_Iterator(t *testing.T) {
t.Run("Seek", func(t *testing.T) {
const n = 100
- m := NewSortedMap(nil)
+ m := NewSortedMap[string, int](nil)
for i := 0; i < n; i += 2 {
m = m.Set(fmt.Sprintf("%04d", i), i)
}
@@ -2014,7 +1970,7 @@ func TestSortedMap_Iterator(t *testing.T) {
for i := 0; i < n; i += 2 {
itr.Seek(fmt.Sprintf("%04d", i))
for j := i; j < n; j += 2 {
- if k, _ := itr.Next(); k != fmt.Sprintf("%04d", j) {
+ if k, _, ok := itr.Next(); !ok || k != fmt.Sprintf("%04d", j) {
t.Fatalf("%d/%d. SortedMapIterator.Next()=%v, expected key %04d", i, j, k, j)
}
}
@@ -2029,7 +1985,7 @@ func TestSortedMap_Iterator(t *testing.T) {
for i := 1; i < n-2; i += 2 {
itr.Seek(fmt.Sprintf("%04d", i))
for j := i + 1; j < n; j += 2 {
- if k, _ := itr.Next(); k != fmt.Sprintf("%04d", j) {
+ if k, _, ok := itr.Next(); !ok || k != fmt.Sprintf("%04d", j) {
t.Fatalf("%d/%d. SortedMapIterator.Next()=%v, expected key %04d", i, j, k, j)
}
}
@@ -2043,7 +1999,7 @@ func TestSortedMap_Iterator(t *testing.T) {
itr := m.Iterator()
itr.Seek("")
for i := 0; i < n; i += 2 {
- if k, _ := itr.Next(); k != fmt.Sprintf("%04d", i) {
+ if k, _, ok := itr.Next(); !ok || k != fmt.Sprintf("%04d", i) {
t.Fatalf("%d. SortedMapIterator.Next()=%v, expected key %04d", i, k, i)
}
}
@@ -2054,7 +2010,7 @@ func TestSortedMap_Iterator(t *testing.T) {
t.Run("AfterLast", func(t *testing.T) {
itr := m.Iterator()
itr.Seek("1000")
- if k, _ := itr.Next(); k != nil {
+ if k, _, ok := itr.Next(); ok {
t.Fatalf("0. SortedMapIterator.Next()=%v, expected nil key", k)
} else if !itr.Done() {
t.Fatalf("SortedMapIterator.Done()=true, expected false")
@@ -2078,7 +2034,7 @@ func TestNewHasher(t *testing.T) {
t.Run("uint64", func(t *testing.T) { testNewHasher(t, uint64(100)) })
t.Run("string", func(t *testing.T) { testNewHasher(t, "foo") })
- t.Run("byteSlice", func(t *testing.T) { testNewHasher(t, []byte("foo")) })
+ //t.Run("byteSlice", func(t *testing.T) { testNewHasher(t, []byte("foo")) })
})
t.Run("reflection", func(t *testing.T) {
@@ -2093,7 +2049,7 @@ func TestNewHasher(t *testing.T) {
})
}
-func testNewHasher(t *testing.T, v interface{}) {
+func testNewHasher[V constraints.Ordered](t *testing.T, v V) {
t.Helper()
h := NewHasher(v)
h.Hash(v)
@@ -2117,7 +2073,7 @@ func TestNewComparer(t *testing.T) {
t.Run("uint64", func(t *testing.T) { testNewComparer(t, uint64(100), uint64(101)) })
t.Run("string", func(t *testing.T) { testNewComparer(t, "bar", "foo") })
- t.Run("byteSlice", func(t *testing.T) { testNewComparer(t, []byte("bar"), []byte("foo")) })
+ //t.Run("byteSlice", func(t *testing.T) { testNewComparer(t, []byte("bar"), []byte("foo")) })
})
t.Run("reflection", func(t *testing.T) {
@@ -2132,7 +2088,7 @@ func TestNewComparer(t *testing.T) {
})
}
-func testNewComparer(t *testing.T, x, y interface{}) {
+func testNewComparer[T constraints.Ordered](t *testing.T, x, y T) {
t.Helper()
c := NewComparer(x)
if c.Compare(x, y) != -1 {
@@ -2146,16 +2102,16 @@ func testNewComparer(t *testing.T, x, y interface{}) {
// TSortedMap represents a combined immutable and stdlib sorted map.
type TSortedMap struct {
- im, prev *SortedMap
- builder *SortedMapBuilder
+ im, prev *SortedMap[int, int]
+ builder *SortedMapBuilder[int, int]
std map[int]int
keys []int
}
func NewTSortedMap() *TSortedMap {
return &TSortedMap{
- im: NewSortedMap(nil),
- builder: NewSortedMapBuilder(nil),
+ im: NewSortedMap[int, int](nil),
+ builder: NewSortedMapBuilder[int, int](nil),
std: make(map[int]int),
}
}
@@ -2235,10 +2191,10 @@ func (m *TSortedMap) Validate() error {
return nil
}
-func (m *TSortedMap) validateForwardIterator(itr *SortedMapIterator) error {
+func (m *TSortedMap) validateForwardIterator(itr *SortedMapIterator[int, int]) error {
for i, k0 := range m.keys {
v0 := m.std[k0]
- if k1, v1 := itr.Next(); k0 != k1 || v0 != v1 {
+ if k1, v1, ok := itr.Next(); !ok || k0 != k1 || v0 != v1 {
return fmt.Errorf("%d. SortedMapIterator.Next()=<%v,%v>, expected <%v,%v>", i, k1, v1, k0, v0)
}
@@ -2247,18 +2203,18 @@ func (m *TSortedMap) validateForwardIterator(itr *SortedMapIterator) error {
return fmt.Errorf("%d. SortedMapIterator.Done()=%v, expected %v", i, v, done)
}
}
- if k, v := itr.Next(); k != nil || v != nil {
+ if k, v, ok := itr.Next(); ok {
return fmt.Errorf("SortedMapIterator.Next()=<%v,%v>, expected nil after done", k, v)
}
return nil
}
-func (m *TSortedMap) validateBackwardIterator(itr *SortedMapIterator) error {
+func (m *TSortedMap) validateBackwardIterator(itr *SortedMapIterator[int, int]) error {
itr.Last()
for i := len(m.keys) - 1; i >= 0; i-- {
k0 := m.keys[i]
v0 := m.std[k0]
- if k1, v1 := itr.Prev(); k0 != k1 || v0 != v1 {
+ if k1, v1, ok := itr.Prev(); !ok || k0 != k1 || v0 != v1 {
return fmt.Errorf("%d. SortedMapIterator.Prev()=<%v,%v>, expected <%v,%v>", i, k1, v1, k0, v0)
}
@@ -2267,7 +2223,7 @@ func (m *TSortedMap) validateBackwardIterator(itr *SortedMapIterator) error {
return fmt.Errorf("%d. SortedMapIterator.Done()=%v, expected %v", i, v, done)
}
}
- if k, v := itr.Prev(); k != nil || v != nil {
+ if k, v, ok := itr.Prev(); ok {
return fmt.Errorf("SortedMapIterator.Prev()=<%v,%v>, expected nil after done", k, v)
}
return nil
@@ -2275,7 +2231,7 @@ func (m *TSortedMap) validateBackwardIterator(itr *SortedMapIterator) error {
func BenchmarkSortedMap_Set(b *testing.B) {
b.ReportAllocs()
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, int](nil)
for i := 0; i < b.N; i++ {
m = m.Set(i, i)
}
@@ -2284,7 +2240,7 @@ func BenchmarkSortedMap_Set(b *testing.B) {
func BenchmarkSortedMap_Delete(b *testing.B) {
const n = 10000
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, int](nil)
for i := 0; i < n; i++ {
m = m.Set(i, i)
}
@@ -2298,7 +2254,7 @@ func BenchmarkSortedMap_Delete(b *testing.B) {
func BenchmarkSortedMap_Iterator(b *testing.B) {
const n = 10000
- m := NewSortedMap(nil)
+ m := NewSortedMap[int, int](nil)
for i := 0; i < 10000; i++ {
m = m.Set(i, i)
}
@@ -2328,7 +2284,7 @@ func BenchmarkSortedMap_Iterator(b *testing.B) {
func BenchmarkSortedMapBuilder_Set(b *testing.B) {
b.ReportAllocs()
- builder := NewSortedMapBuilder(nil)
+ builder := NewSortedMapBuilder[int, int](nil)
for i := 0; i < b.N; i++ {
builder.Set(i, i)
}
@@ -2337,7 +2293,7 @@ func BenchmarkSortedMapBuilder_Set(b *testing.B) {
func BenchmarkSortedMapBuilder_Delete(b *testing.B) {
const n = 1000000
- builder := NewSortedMapBuilder(nil)
+ builder := NewSortedMapBuilder[int, int](nil)
for i := 0; i < n; i++ {
builder.Set(i, i)
}
@@ -2350,7 +2306,7 @@ func BenchmarkSortedMapBuilder_Delete(b *testing.B) {
}
func ExampleSortedMap_Set() {
- m := NewSortedMap(nil)
+ m := NewSortedMap[string, any](nil)
m = m.Set("foo", "bar")
m = m.Set("baz", 100)
@@ -2369,7 +2325,7 @@ func ExampleSortedMap_Set() {
}
func ExampleSortedMap_Delete() {
- m := NewSortedMap(nil)
+ m := NewSortedMap[string, any](nil)
m = m.Set("foo", "bar")
m = m.Set("baz", 100)
m = m.Delete("baz")
@@ -2385,7 +2341,7 @@ func ExampleSortedMap_Delete() {
}
func ExampleSortedMap_Iterator() {
- m := NewSortedMap(nil)
+ m := NewSortedMap[string, any](nil)
m = m.Set("strawberry", 900)
m = m.Set("kiwi", 300)
m = m.Set("apple", 100)
@@ -2398,7 +2354,7 @@ func ExampleSortedMap_Iterator() {
itr := m.Iterator()
for !itr.Done() {
- k, v := itr.Next()
+ k, v, _ := itr.Next()
fmt.Println(k, v)
}
// Output:
@@ -2414,7 +2370,7 @@ func ExampleSortedMap_Iterator() {
}
func ExampleSortedMapBuilder_Set() {
- b := NewSortedMapBuilder(nil)
+ b := NewSortedMapBuilder[string, any](nil)
b.Set("foo", "bar")
b.Set("baz", 100)
@@ -2434,7 +2390,7 @@ func ExampleSortedMapBuilder_Set() {
}
func ExampleSortedMapBuilder_Delete() {
- b := NewSortedMapBuilder(nil)
+ b := NewSortedMapBuilder[string, any](nil)
b.Set("foo", "bar")
b.Set("baz", 100)
b.Delete("baz")
@@ -2479,27 +2435,27 @@ func uniqueIntSlice(a []int) []int {
}
// mockHasher represents a mock implementation of immutable.Hasher.
-type mockHasher struct {
- hash func(value interface{}) uint32
- equal func(a, b interface{}) bool
+type mockHasher[K constraints.Ordered] struct {
+ hash func(value K) uint32
+ equal func(a, b K) bool
}
// Hash executes the mocked HashFn function.
-func (h *mockHasher) Hash(value interface{}) uint32 {
+func (h *mockHasher[K]) Hash(value K) uint32 {
return h.hash(value)
}
// Equal executes the mocked EqualFn function.
-func (h *mockHasher) Equal(a, b interface{}) bool {
+func (h *mockHasher[K]) Equal(a, b K) bool {
return h.equal(a, b)
}
// mockComparer represents a mock implementation of immutable.Comparer.
-type mockComparer struct {
- compare func(a, b interface{}) int
+type mockComparer[K constraints.Ordered] struct {
+ compare func(a, b K) int
}
// Compare executes the mocked CompreFn function.
-func (h *mockComparer) Compare(a, b interface{}) int {
+func (h *mockComparer[K]) Compare(a, b K) int {
return h.compare(a, b)
}