Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions common/sorted_set/sorted_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ func (s *SortedSet[T]) Add(v T) {

// AddAll adds all of the elements from the other SortedSet to this one.
func (s *SortedSet[T]) AddAll(other *SortedSet[T]) {
if s == nil || s.tree == nil || other == nil || other.tree == nil {
return
}
other.tree.Ascend(func(v T) bool {
s.Add(v)
return true
Expand All @@ -75,6 +78,9 @@ func (s *SortedSet[T]) AddAll(other *SortedSet[T]) {
// Filter creates a new SortedSet containing only the elements from this one for
// which the passed predicate evaluates true.
func (s *SortedSet[T]) Filter(predicate func(T) bool) *SortedSet[T] {
if s == nil || s.tree == nil {
return nil
}
new := &SortedSet[T]{
tree: s.tree.Clone(),
}
Expand All @@ -93,6 +99,9 @@ func (s *SortedSet[T]) Filter(predicate func(T) bool) *SortedSet[T] {
// of mutations on both sets may be worse while initial copies are (lazily)
// made.
func (s *SortedSet[T]) Clone() *SortedSet[T] {
if s == nil || s.tree == nil {
return nil
}
return &SortedSet[T]{
tree: s.tree.Clone(),
}
Expand Down
38 changes: 33 additions & 5 deletions common/sorted_set/sorted_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestInsert(t *testing.T) {
got := s.SortedSlice()
want := []string{}
if !reflect.DeepEqual(got, want) {
t.Errorf("Before insert: wanted %v got %v")
t.Errorf("Before insert: wanted %v got %v", want, got)
}

if s.Contains("cheese") {
Expand All @@ -73,7 +73,7 @@ func TestInsert(t *testing.T) {
got := s.SortedSlice()
want := []string{"cheese"}
if !reflect.DeepEqual(got, want) {
t.Errorf("After one insert: wanted %v got %v")
t.Errorf("After one insert: wanted %v got %v", want, got)
}

if !s.Contains("cheese") {
Expand All @@ -93,7 +93,7 @@ func TestInsert(t *testing.T) {
got := s.SortedSlice()
want := []string{"cheese"}
if !reflect.DeepEqual(got, want) {
t.Errorf("After two inserts: wanted %v got %v")
t.Errorf("After two inserts: wanted %v got %v", want, got)
}

if !s.Contains("cheese") {
Expand All @@ -113,7 +113,7 @@ func TestInsert(t *testing.T) {
got := s.SortedSlice()
want := []string{"cheese", "onions"}
if !reflect.DeepEqual(got, want) {
t.Errorf("After three inserts: wanted %v got %v")
t.Errorf("After three inserts: wanted %v got %v", want, got)
}

if !s.Contains("cheese") {
Expand All @@ -133,7 +133,7 @@ func TestInsert(t *testing.T) {
got := s.SortedSlice()
want := []string{"brie", "cheese", "onions"}
if !reflect.DeepEqual(got, want) {
t.Errorf("After four inserts: wanted %v got %v")
t.Errorf("After four inserts: wanted %v got %v", want, got)
}

if !s.Contains("cheese") {
Expand Down Expand Up @@ -295,3 +295,31 @@ func TestFilterCustomComparator(t *testing.T) {
t.Errorf("want %v got %v", want2, got2)
}
}
func TestSortedSet_NilSafety(t *testing.T) {
var nilSet *ss.SortedSet[string]

if nilSet.Len() != 0 {
t.Errorf("nilSet.Len() = %v, want 0", nilSet.Len())
}
if nilSet.Contains("apple") {
t.Errorf("nilSet.Contains() = true, want false")
}
if got := nilSet.SortedSlice(); got != nil {
t.Errorf("nilSet.SortedSlice() = %v, want nil", got)
}
if got := nilSet.Clone(); got != nil {
t.Errorf("nilSet.Clone() = %v, want nil", got)
}
if got := nilSet.Filter(func(s string) bool { return true }); got != nil {
t.Errorf("nilSet.Filter() = %v, want nil", got)
}

// AddAll with nil other or nil receiver should not panic
s := ss.NewSortedSet([]string{"banana"})
s.AddAll(nil)
if s.Len() != 1 || !s.Contains("banana") {
t.Errorf("s.AddAll(nil) corrupted set: %v", s.SortedSlice())
}

nilSet.AddAll(s) // should be a safe no-op
}