Skip to content

Commit

Permalink
slices: add DeleteFunc
Browse files Browse the repository at this point in the history
Fixes golang#54768

Change-Id: I588ae33c13e0bbd9d324c11771667b22a864047d
Reviewed-on: https://go-review.googlesource.com/c/go/+/483175
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Eli Bendersky <eliben@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
  • Loading branch information
ianlancetaylor authored and eric committed Sep 7, 2023
1 parent f16c71a commit cc3d575
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions api/next/54768.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pkg slices, func DeleteFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1) bool) $0 #54768
26 changes: 26 additions & 0 deletions src/slices/slices.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,32 @@ func Delete[S ~[]E, E any](s S, i, j int) S {
return append(s[:i], s[j:]...)
}

// DeleteFunc removes any elements from s for which del returns true,
// returning the modified slice.
// DeleteFunc modifies the contents of the slice s;
// it does not create a new slice.
// When DeleteFunc removes m elements, it might not modify the elements
// s[len(s)-m:len(s)]. If those elements contain pointers you might consider
// zeroing those elements so that objects they reference can be garbage
// collected.
func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
// Don't start copying elements until we find one to delete.
for i, v := range s {
if del(v) {
j := i
for i++; i < len(s); i++ {
v = s[i]
if !del(v) {
s[j] = v
j++
}
}
return s[:j]
}
}
return s
}

// Replace replaces the elements s[i:j] by the given v, and returns the
// modified slice. Replace panics if s[i:j] is not a valid slice of s.
func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
Expand Down
46 changes: 46 additions & 0 deletions src/slices/slices_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,52 @@ func TestDelete(t *testing.T) {
}
}

var deleteFuncTests = []struct {
s []int
fn func(int) bool
want []int
}{
{
nil,
func(int) bool { return true },
nil,
},
{
[]int{1, 2, 3},
func(int) bool { return true },
nil,
},
{
[]int{1, 2, 3},
func(int) bool { return false },
[]int{1, 2, 3},
},
{
[]int{1, 2, 3},
func(i int) bool { return i > 2 },
[]int{1, 2},
},
{
[]int{1, 2, 3},
func(i int) bool { return i < 2 },
[]int{2, 3},
},
{
[]int{10, 2, 30},
func(i int) bool { return i >= 10 },
[]int{2},
},
}

func TestDeleteFunc(t *testing.T) {
for i, test := range deleteFuncTests {
copy := Clone(test.s)
if got := DeleteFunc(copy, test.fn); !Equal(got, test.want) {
t.Errorf("DeleteFunc case %d: got %v, want %v", i, got, test.want)
}
}
}

func panics(f func()) (b bool) {
defer func() {
if x := recover(); x != nil {
Expand Down

0 comments on commit cc3d575

Please sign in to comment.