Skip to content

Commit 7bbe17c

Browse files
authored
#13 - refactor: update Copy() function and interface implementations (#24)
* #13 - refactor: update Copy() function and interface implementations This commit focuses on refactoring the Copy() function implementation and making the internal interfaces more consistent, while removing unused code. - Modify Copy() to check for baseInternal interface implementation - Update copy() method signatures to return baseInternal[V] consistently - Remove unused KV-related types and functions - Remove comfyContainsValue and comfyContainsKV functions - Initialize empty slices with nil instead of make() - Add test cases for Copy() function and edge cases - Update interface definitions for mapInternal * #13 - added missed test file * #13 - supplemented Copy() tests * #13 - supplemented Copy() tests
1 parent 8588425 commit 7bbe17c

File tree

11 files changed

+187
-40
lines changed

11 files changed

+187
-40
lines changed

cmp_cases_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,11 @@ func getMinCases[C any](builder testCollectionBuilder[C]) []testCase[C, int] {
367367
coll: builder.Three(),
368368
want1: 111,
369369
},
370+
{
371+
name: "Min() on three-item collection reversed",
372+
coll: builder.ThreeRev(),
373+
want1: 111,
374+
},
370375
{
371376
name: "Min() on six-item collection",
372377
coll: builder.SixWithDuplicates(),

definitions.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,6 @@ type Comparator[V any] = func(a, b V) int
3434
// PairComparator is a comparator function for key-value pairs.
3535
type PairComparator[K comparable, V any] = Comparator[Pair[K, V]]
3636

37-
// KKVistor is a visitor function for key-value pairs.
38-
type KVVistor[K comparable, V any] = func(i int, k K, val V)
39-
40-
// KVPredicate is a predicate function for key-value pairs.
41-
type KVPredicate[K comparable, V any] = func(i int, k K, val V) (valid bool)
42-
43-
// KVReducer is a reducer function for key-value pairs.
44-
type KVReducer[K comparable, V any] = func(keyAcc K, valueAcc V, currentKey K, currentValue V) (K, V)
45-
4637
// Base is the base interface for all collections.
4738
type Base[V any] interface {
4839
// Contains returns true if the collection contains an element that matches the predicate.

definitions_internal.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
type baseInternal[V any] interface {
1111
Base[V]
12-
copy() Base[V]
12+
copy() baseInternal[V]
1313
// values() iter.Seq[V] // TODO
1414
}
1515

@@ -65,7 +65,7 @@ type listInternal[V any] interface {
6565

6666
type mapInternal[K comparable, V any] interface {
6767
Map[K, V]
68-
copy() mapInternal[K, V]
68+
baseInternal[Pair[K, V]]
6969
// keyValues() iter.Seq2[K, V] // TODO
7070
prependAll(pairs []Pair[K, V])
7171
remove(k K)

functions.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@ package coll
33
// Public:
44

55
// Copy creates a copy of the given collection.
6-
func Copy[C baseInternal[V], V any](c C) C {
7-
return c.copy().(C)
6+
func Copy[C Base[V], V any](coll C) C {
7+
// check if c is of type baseInternal[T]:
8+
if c, ok := any(coll).(baseInternal[V]); ok {
9+
return c.copy().(C)
10+
}
11+
panic("Copy() requires a collection that implements the baseInternal interface")
812
}
913

1014
//// Filter creates a new, filtered collection from the given collection.

functions_internal.go

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,6 @@ func comfyContains[C Base[V], V any](coll C, predicate Predicate[V]) bool {
3232
return found
3333
}
3434

35-
func comfyContainsValue[C Base[V], V cmp.Ordered](coll C, search V) bool {
36-
return comfyContains(coll, func(_ int, v V) bool {
37-
return v == search
38-
})
39-
}
40-
41-
func comfyContainsKV[M Map[K, V], K comparable, V any](m M, predicate KVPredicate[K, V]) bool {
42-
found := false
43-
m.EachUntil(func(i int, p Pair[K, V]) bool {
44-
if predicate(i, p.Key(), p.Val()) {
45-
found = true
46-
return false
47-
}
48-
49-
return true
50-
})
51-
52-
return found
53-
}
54-
5535
func comfyCount[C Base[V], V any](coll C, predicate Predicate[V]) int {
5636
count := 0
5737
coll.Each(func(i int, v V) {

functions_test.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package coll
2+
3+
import (
4+
"iter"
5+
"reflect"
6+
"testing"
7+
)
8+
9+
type baseFakeWithoutInternal[V any] struct{}
10+
11+
func (*baseFakeWithoutInternal[V]) Contains(_ Predicate[V]) bool {
12+
return false
13+
}
14+
15+
func (*baseFakeWithoutInternal[V]) Count(_ Predicate[V]) int {
16+
return 0
17+
}
18+
19+
func (*baseFakeWithoutInternal[V]) Each(_ Visitor[V]) {
20+
}
21+
22+
func (*baseFakeWithoutInternal[V]) EachUntil(_ Predicate[V]) {
23+
}
24+
25+
func (*baseFakeWithoutInternal[V]) Find(_ Predicate[V], defaultValue V) V {
26+
return defaultValue
27+
}
28+
29+
func (*baseFakeWithoutInternal[V]) Fold(_ Reducer[V], initial V) (result V) {
30+
return initial
31+
}
32+
33+
func (*baseFakeWithoutInternal[V]) IsEmpty() bool {
34+
return true
35+
}
36+
37+
func (*baseFakeWithoutInternal[V]) Len() int {
38+
return 0
39+
}
40+
41+
func (*baseFakeWithoutInternal[V]) Search(_ Predicate[V]) (val V, found bool) {
42+
return val, false
43+
}
44+
45+
func (*baseFakeWithoutInternal[V]) Reduce(_ Reducer[V]) (result V, err error) {
46+
return result, nil
47+
}
48+
49+
func (*baseFakeWithoutInternal[V]) ToSlice() []V {
50+
return nil
51+
}
52+
53+
func (*baseFakeWithoutInternal[V]) Values() iter.Seq[V] {
54+
return nil
55+
}
56+
57+
func Test_Copy_forEachFlatCollection(t *testing.T) {
58+
cases := []struct {
59+
name string
60+
coll LinearMutable[int]
61+
}{
62+
{
63+
name: "Copy() on empty Sequence",
64+
coll: NewSequence[int](),
65+
},
66+
{
67+
name: "Copy() three-item sequence",
68+
coll: NewSequenceFrom([]int{111, 222, 333}),
69+
},
70+
{
71+
name: "Copy() on empty CmpSequence",
72+
coll: NewCmpSequence[int](),
73+
},
74+
{
75+
name: "Copy() three-item CmpSequence",
76+
coll: NewCmpSequenceFrom([]int{111, 222, 333}),
77+
},
78+
}
79+
for _, tt := range cases {
80+
t.Run(tt.name, func(t *testing.T) {
81+
got := Copy(tt.coll)
82+
if !reflect.DeepEqual(got, tt.coll) {
83+
t.Errorf("Copy() = %v, want %v", got, tt.coll)
84+
}
85+
86+
tt.coll.Append(999)
87+
if reflect.DeepEqual(got, tt.coll) {
88+
t.Errorf("Copy() did not create a deep copy")
89+
}
90+
if got.Len() == tt.coll.Len() {
91+
t.Errorf(
92+
"Copy length %d should be different from original length %d after modification",
93+
got.Len(),
94+
tt.coll.Len(),
95+
)
96+
}
97+
})
98+
}
99+
}
100+
101+
func Test_Copy_forEachMap(t *testing.T) {
102+
cases := []struct {
103+
name string
104+
coll Map[int, int]
105+
}{
106+
{
107+
name: "Copy() on empty Map",
108+
coll: NewMap[int, int](),
109+
},
110+
{
111+
name: "Copy() three-item Map",
112+
coll: NewMapFrom([]Pair[int, int]{
113+
NewPair(1, 111),
114+
NewPair(2, 222),
115+
NewPair(3, 333),
116+
}),
117+
},
118+
{
119+
name: "Copy() on empty CmpMap",
120+
coll: NewCmpMap[int, int](),
121+
},
122+
{
123+
name: "Copy() three-item CmpMap",
124+
coll: NewCmpMapFrom([]Pair[int, int]{
125+
NewPair(1, 111),
126+
NewPair(2, 222),
127+
NewPair(3, 333),
128+
}),
129+
},
130+
}
131+
for _, tt := range cases {
132+
t.Run(tt.name, func(t *testing.T) {
133+
got := Copy(tt.coll)
134+
if !reflect.DeepEqual(got, tt.coll) {
135+
t.Errorf("Copy() = %v, want %v", got, tt.coll)
136+
}
137+
138+
tt.coll.Append(NewPair(4, 444))
139+
if reflect.DeepEqual(got, tt.coll) {
140+
t.Errorf("Copy() did not create a deep copy")
141+
}
142+
if got.Len() == tt.coll.Len() {
143+
t.Errorf(
144+
"Copy length %d should be different from original length %d after modification",
145+
got.Len(),
146+
tt.coll.Len(),
147+
)
148+
}
149+
})
150+
}
151+
}
152+
153+
func Test_Copy_ofCollectionWithoutInternal(t *testing.T) {
154+
t.Run("Copy() on collection without internal", func(t *testing.T) {
155+
coll := &baseFakeWithoutInternal[int]{}
156+
defer func() {
157+
r := recover()
158+
if r == nil {
159+
t.Errorf("Copy() did not panic")
160+
}
161+
if r != "Copy() requires a collection that implements the baseInternal interface" {
162+
t.Errorf("Copy() panicked with wrong error: %v", r)
163+
}
164+
}()
165+
Copy(coll)
166+
})
167+
}

map.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ func (c *comfyMap[K, V]) Values() iter.Seq[Pair[K, V]] {
325325
// Private functions:
326326

327327
//nolint:unused
328-
func (c *comfyMap[K, V]) copy() mapInternal[K, V] {
328+
func (c *comfyMap[K, V]) copy() baseInternal[Pair[K, V]] {
329329
newCm := &comfyMap[K, V]{
330330
s: []Pair[K, V](nil),
331331
m: make(map[K]Pair[K, V]),

mapcmp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ func (c *comfyCmpMap[K, V]) Values() iter.Seq[Pair[K, V]] {
407407

408408
// Private:
409409

410-
func (c *comfyCmpMap[K, V]) copy() mapInternal[K, V] {
410+
func (c *comfyCmpMap[K, V]) copy() baseInternal[Pair[K, V]] {
411411
newCm := NewCmpMap[K, V]().(*comfyCmpMap[K, V])
412412
for _, pair := range c.s {
413413
newCm.set(pair.copy())

sequence.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type comfySeq[V any] struct {
1212
// NewSequence creates a new LinearMutable instance.
1313
func NewSequence[V any]() Sequence[V] {
1414
return &comfySeq[V]{
15-
s: make([]V, 0),
15+
s: []V(nil),
1616
}
1717
}
1818

@@ -257,7 +257,7 @@ func (c *comfySeq[V]) Values() iter.Seq[V] {
257257
// Private:
258258

259259
//nolint:unused
260-
func (c *comfySeq[V]) copy() Base[V] {
260+
func (c *comfySeq[V]) copy() baseInternal[V] {
261261
newCl := &comfySeq[V]{
262262
s: []V(nil),
263263
}

sequence_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ func TestNewSequence(t *testing.T) {
9696
if intSeq == nil {
9797
t.Error("NewSequence[int]() returned nil")
9898
}
99-
if !reflect.DeepEqual(intSeq, &comfySeq[int]{s: make([]int, 0)}) {
99+
if !reflect.DeepEqual(intSeq, &comfySeq[int]{s: []int(nil)}) {
100100
t.Error("NewSequence[int]() did not return a comfySeq[int]")
101101
}
102102

103103
stringSeq := NewSequence[string]()
104104
if stringSeq == nil {
105105
t.Error("NewSequence[string]() returned nil")
106106
}
107-
if !reflect.DeepEqual(stringSeq, &comfySeq[string]{s: make([]string, 0)}) {
107+
if !reflect.DeepEqual(stringSeq, &comfySeq[string]{s: []string(nil)}) {
108108
t.Error("NewSequence[int]() did not return a comfySeq[int]")
109109
}
110110
})

0 commit comments

Comments
 (0)