]> Cypherpunks.ru repositories - gostls13.git/commitdiff
slices: add DeleteFunc
authorIan Lance Taylor <iant@golang.org>
Fri, 7 Apr 2023 21:03:55 +0000 (14:03 -0700)
committerGopher Robot <gobot@golang.org>
Fri, 7 Apr 2023 22:25:51 +0000 (22:25 +0000)
Fixes #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>

api/next/54768.txt [new file with mode: 0644]
src/slices/slices.go
src/slices/slices_test.go

diff --git a/api/next/54768.txt b/api/next/54768.txt
new file mode 100644 (file)
index 0000000..b824c50
--- /dev/null
@@ -0,0 +1 @@
+pkg slices, func DeleteFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1) bool) $0 #54768
index 1a837c53c190614313608e3747149816a18ccce1..ea1dea573c9111af760a0c0e2c9305c7430be875 100644 (file)
@@ -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 {
index 80efb34fc8a718d41a6278f7c3a8824254b566ad..720e731ddf2b5fe6ac349ac2554e4dafa7ec43b6 100644 (file)
@@ -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 {