Skip to content

Commit dc2152d

Browse files
committed
bug(orderedmap): provide support for callbacks deleting items.
1 parent 44d3bac commit dc2152d

File tree

3 files changed

+39
-9
lines changed

3 files changed

+39
-9
lines changed

orderedmap/slice.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ func (s *Slice[K, V]) Range(f func(key K, value V) bool) {
5252
}
5353
}
5454

55+
func (s *Slice[K, V]) RangeMutable(f func(key K, value V) bool) {
56+
order := make([]K, len(s.order))
57+
copy(order, s.order)
58+
store := make(map[K]V, len(s.store))
59+
for k, v := range s.store {
60+
store[k] = v
61+
}
62+
snap := Slice[K, V]{
63+
order: order,
64+
store: store,
65+
stable: s.stable,
66+
}
67+
snap.Range(f)
68+
}
69+
5570
func (s *Slice[K, V]) Store(k K, v V) {
5671
_, loaded := s.store[k]
5772
if !loaded {

orderedmap/slice_transparent_test.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,23 @@ func TestSlice_Range_Mutators(t *testing.T) {
109109
}
110110
}
111111
tests := [...]struct {
112-
name string
113-
fn func(*testType) func(key, value int) bool
114-
expectedPanic error
115-
expected []int
112+
name string
113+
useRangeMutable bool
114+
fn func(*testType) func(key, value int) bool
115+
expectedPanic error
116+
expected []int
116117
}{
117-
{"nop/plain range", fnNop, nil, []int{0, 0, 0, 1, 1, 2, 2, 3, 3}},
118+
{"nop/plain range", false, fnNop, nil, []int{0, 0, 0, 1, 1, 2, 2, 3, 3}},
119+
{"nop/mutable", true, fnNop, nil, []int{0, 0, 0, 1, 1, 2, 2, 3, 3}},
118120
// Mutating a value moves it to the end of the map.
119-
{"mutateOne/plain range", fnMutateOne, nil, []int{0, 0, 0, 2, 2, 3, 3, 1, 10}},
121+
{"mutateOne/plain range", false, fnMutateOne, nil, []int{0, 0, 0, 2, 2, 3, 3, 1, 10}},
122+
{"mutateOne/mutable", false, fnMutateOne, nil, []int{0, 0, 0, 2, 2, 3, 3, 1, 10}},
120123
// Store a value moves it to the end of the map.
121-
{"insertOne/plain range", fnInsertOne, nil, []int{0, 0, 0, 1, 1, 2, 2, 3, 3, 10, 10}},
124+
{"insertOne/plain range", false, fnInsertOne, nil, []int{0, 0, 0, 1, 1, 2, 2, 3, 3, 10, 10}},
125+
{"insertOne/mutable", false, fnInsertOne, nil, []int{0, 0, 0, 1, 1, 2, 2, 3, 3, 10, 10}},
122126
// This is why we need to some form of mutation support: observe the unexpected results.
123-
{"deleteOdd/plain range", fnDeleteOdd, errors.New(""), []int{0, 0, 0, 2, 2}},
127+
{"deleteOdd/plain range", false, fnDeleteOdd, errors.New(""), []int{0, 0, 0, 2, 2}},
128+
{"deleteOdd/mutable", true, fnDeleteOdd, nil, []int{0, 0, 0, 2, 2}},
124129
}
125130
for _, test := range tests {
126131
t.Run(test.name, func(t *testing.T) {
@@ -133,7 +138,11 @@ func TestSlice_Range_Mutators(t *testing.T) {
133138
actualPanic = err.(error)
134139
}
135140
}()
136-
input.Range(test.fn(&input))
141+
if test.useRangeMutable {
142+
input.RangeMutable(test.fn(&input))
143+
} else {
144+
input.Range(test.fn(&input))
145+
}
137146
}()
138147
actual := transform(input)
139148
t1, t2 := reflect.TypeOf(actualPanic), reflect.TypeOf(test.expectedPanic)

types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ type OrderedMap[K comparable, V any] interface {
1111
Store(key K, value V)
1212
}
1313

14+
type OrderedMapWithRangeMutable[K comparable, V any] interface {
15+
OrderedMap[K, V]
16+
// RangeMutable allows its callbacks to delete map entries, operating on a snapshot.
17+
RangeMutable(func(key K, value V) bool)
18+
}
19+
1420
// Queue is a generic queue with no concurrency guarantees.
1521
// Instantiate by queue.New<implementation>Queue(sizeHint).
1622
// The size hint MAY be used by some implementations to optimize storage.

0 commit comments

Comments
 (0)