]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/slices/slices.go
slices: update doc for Delete and Replace
[gostls13.git] / src / slices / slices.go
index c8eacae90e541107afb69ad073e404391b8b9d49..4c398557ff4241565f5ac776d28561cc53913abb 100644 (file)
@@ -27,7 +27,7 @@ func Equal[S ~[]E, E comparable](s1, s2 S) bool {
        return true
 }
 
-// EqualFunc reports whether two slices are equal using a comparison
+// EqualFunc reports whether two slices are equal using an equality
 // function on each pair of elements. If the lengths are different,
 // EqualFunc returns false. Otherwise, the elements are compared in
 // increasing index order, and the comparison stops at the first index
@@ -68,7 +68,7 @@ func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) int {
        return 0
 }
 
-// CompareFunc is like Compare but uses a custom comparison function on each
+// CompareFunc is like [Compare] but uses a custom comparison function on each
 // pair of elements.
 // The result is the first non-zero result of cmp; if cmp always
 // returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
@@ -130,11 +130,14 @@ func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
 // Insert panics if i is out of range.
 // This function is O(len(s) + len(v)).
 func Insert[S ~[]E, E any](s S, i int, v ...E) S {
+       n := len(s)
        m := len(v)
        if m == 0 {
+               // Panic if i is not in the range [0:n] inclusive.
+               // See issue 63913.
+               _ = s[:n:n][i:]
                return s
        }
-       n := len(s)
        if i == n {
                return append(s, v...)
        }
@@ -209,8 +212,7 @@ func Insert[S ~[]E, E any](s S, i int, v ...E) S {
 }
 
 // Delete removes the elements s[i:j] from s, returning the modified slice.
-// Delete panics if s[i:j] is not a valid slice of s.
-// Delete modifies the contents of the slice s; it does not create a new slice.
+// Delete panics if j > len(s) or s[i:j] is not a valid slice of s.
 // Delete is O(len(s)-j), so if many items must be deleted, it is better to
 // make a single call deleting them all together than to delete one at a time.
 // Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those
@@ -224,34 +226,30 @@ func Delete[S ~[]E, E any](s S, i, j int) S {
 
 // 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 {
+       i := IndexFunc(s, del)
+       if i == -1 {
+               return 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]
+       for j := i + 1; j < len(s); j++ {
+               if v := s[j]; !del(v) {
+                       s[i] = v
+                       i++
                }
        }
-       return s
+       return s[:i]
 }
 
 // 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.
+// modified slice.
+// Replace panics if j > len(s) or s[i:j] is not a valid slice of s.
 func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
-       _ = s[i:j] // verify that i:j is a valid subslice
+       _ = s[i:j] // bounds check
 
        if i == j {
                return Insert(s, i, v...)
@@ -274,9 +272,7 @@ func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
        if i+len(v) <= j {
                // Easy, as v fits in the deleted portion.
                copy(r[i:], v)
-               if i+len(v) != j {
-                       copy(r[i+len(v):], s[j:])
-               }
+               copy(r[i+len(v):], s[j:])
                return r
        }
 
@@ -339,16 +335,14 @@ func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
 // Clone returns a copy of the slice.
 // The elements are copied using assignment, so this is a shallow clone.
 func Clone[S ~[]E, E any](s S) S {
-       // Preserve nil in case it matters.
-       if s == nil {
-               return nil
-       }
-       return append(S([]E{}), s...)
+       // The s[:0:0] preserves nil in case it matters.
+       return append(s[:0:0], s...)
 }
 
 // Compact replaces consecutive runs of equal elements with a single copy.
 // This is like the uniq command found on Unix.
-// Compact modifies the contents of the slice s; it does not create a new slice.
+// Compact modifies the contents of the slice s and returns the modified slice,
+// which may have a smaller length.
 // When Compact discards m elements in total, 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.
@@ -368,7 +362,8 @@ func Compact[S ~[]E, E comparable](s S) S {
        return s[:i]
 }
 
-// CompactFunc is like Compact but uses a comparison function.
+// CompactFunc is like [Compact] but uses an equality function to compare elements.
+// For runs of elements that compare equal, CompactFunc keeps the first one.
 func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
        if len(s) < 2 {
                return s
@@ -497,3 +492,19 @@ func Reverse[S ~[]E, E any](s S) {
                s[i], s[j] = s[j], s[i]
        }
 }
+
+// Concat returns a new slice concatenating the passed in slices.
+func Concat[S ~[]E, E any](slices ...S) S {
+       size := 0
+       for _, s := range slices {
+               size += len(s)
+               if size < 0 {
+                       panic("len out of range")
+               }
+       }
+       newslice := Grow[S](nil, size)
+       for _, s := range slices {
+               newslice = append(newslice, s...)
+       }
+       return newslice
+}