diff --git a/locked.go b/locked.go index 208e973..47b38a5 100644 --- a/locked.go +++ b/locked.go @@ -101,8 +101,6 @@ func (s *Locked[M]) Iterator(yield func(M) bool) { // Clone returns a new set of the same underlying type. func (s *Locked[M]) Clone() Set[M] { - s.RLock() - defer s.RUnlock() return NewLockedFrom(s.Iterator) } diff --git a/locked_ordered.go b/locked_ordered.go index 2f8d3e5..8c7a8d6 100644 --- a/locked_ordered.go +++ b/locked_ordered.go @@ -97,8 +97,6 @@ func (s *LockedOrdered[M]) Iterator(yield func(M) bool) { // Clone returns a new set of the same underlying type. func (s *LockedOrdered[M]) Clone() Set[M] { - s.RLock() - defer s.RUnlock() return NewLockedOrderedFrom(s.Iterator) } diff --git a/ordered.go b/ordered.go index e26ed61..7847118 100644 --- a/ordered.go +++ b/ordered.go @@ -209,9 +209,8 @@ func (s *Ordered[M]) UnmarshalJSON(d []byte) error { } s.Clear() - s.values = t - for i, v := range s.values { - s.idx[v] = i + for _, v := range t { + s.Add(v) } return nil diff --git a/set.go b/set.go index bd4176f..75c5d4b 100644 --- a/set.go +++ b/set.go @@ -174,8 +174,8 @@ func Disjoint[K comparable](a, b Set[K]) bool { // to the yield function. The index is not stable across iterations. The yield function is called for each element in the // set. If the yield function returns false, the iteration is stopped. func Iter2[K comparable](iter iter.Seq[K]) func(func(i int, k K) bool) { - var i int return func(yield func(i int, k K) bool) { + var i int for k := range iter { if !yield(i, k) { return @@ -220,7 +220,11 @@ func Min[K cmp.Ordered](s Set[K]) K { } // Chunk the set into n sets of equal size. The last set will have fewer elements if the cardinality of the set is not a multiple of n. +// Panics if n <= 0. func Chunk[K comparable](s Set[K], n int) iter.Seq[Set[K]] { + if n <= 0 { + panic("sets.Chunk: n must be > 0") + } return func(yield func(Set[K]) bool) { chunk := s.NewEmpty() for i, v := range Iter2(s.Iterator) { diff --git a/set_test.go b/set_test.go index c616fee..b2c3245 100644 --- a/set_test.go +++ b/set_test.go @@ -1084,3 +1084,33 @@ func TestFirst_Last_LockedOrdered(t *testing.T) { t.Fatalf("expected Last on empty set to return false") } } + +func TestIter2ReusedIteratorResetsIndex(t *testing.T) { + t.Parallel() + + s := New[int]() + s.Add(1) + s.Add(2) + s.Add(3) + + iter2 := Iter2(s.Iterator) + + // First iteration: collect all indices + var firstIndices []int + for i := range iter2 { + firstIndices = append(firstIndices, i) + } + + // Second iteration: indices should start at 0 again + var secondIndices []int + for i := range iter2 { + secondIndices = append(secondIndices, i) + } + + slices.Sort(firstIndices) + slices.Sort(secondIndices) + + if diff := cmp.Diff(firstIndices, secondIndices); diff != "" { + t.Errorf("Iter2 indices differ on second invocation (-first +second):\n%s", diff) + } +} diff --git a/sync.go b/sync.go index eddebbc..845210a 100644 --- a/sync.go +++ b/sync.go @@ -14,8 +14,10 @@ type SyncMap[M comparable] struct { m sync.Map } -var _ Set[int] = new(SyncMap[int]) -var _ driver.Valuer = new(SyncMap[int]) +var ( + _ Set[int] = new(SyncMap[int]) + _ driver.Valuer = new(SyncMap[int]) +) // NewSyncMap returns an empty Set[M] that is backed by a sync.Map, making it safe for concurrent use. // Please read the documentation for [sync.Map] to understand the behavior of modifying the map. @@ -48,11 +50,11 @@ func (s *SyncMap[M]) Contains(m M) bool { func (s *SyncMap[M]) Clear() int { var n int - s.m.Range(func(_, _ interface{}) bool { + s.m.Range(func(k, _ any) bool { + s.m.Delete(k) n++ return true }) - s.m.Clear() return n }