replace strings.Split(N) for strings.Cut() or alternatives

Go 1.18 and up now provides a strings.Cut() which is better suited for
splitting key/value pairs (and similar constructs), and performs better:

```go
func BenchmarkSplit(b *testing.B) {
        b.ReportAllocs()
        data := []string{"12hello=world", "12hello=", "12=hello", "12hello"}
        for i := 0; i < b.N; i++ {
                for _, s := range data {
                        _ = strings.SplitN(s, "=", 2)[0]
                }
        }
}

func BenchmarkCut(b *testing.B) {
        b.ReportAllocs()
        data := []string{"12hello=world", "12hello=", "12=hello", "12hello"}
        for i := 0; i < b.N; i++ {
                for _, s := range data {
                        _, _, _ = strings.Cut(s, "=")
                }
        }
}
```

    BenchmarkSplit
    BenchmarkSplit-10            8244206               128.0 ns/op           128 B/op          4 allocs/op
    BenchmarkCut
    BenchmarkCut-10             54411998                21.80 ns/op            0 B/op          0 allocs/op

While looking at occurrences of `strings.Split()`, I also updated some for alternatives,
or added some constraints; for cases where an specific number of items is expected, I used `strings.SplitN()`
with a suitable limit. This prevents (theoretical) unlimited splits.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2022-11-04 09:05:39 +01:00
parent f90219d472
commit eaedadbed0
19 changed files with 96 additions and 106 deletions

View File

@@ -310,16 +310,16 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
joinNs := context.StringSlice("with-ns")
for _, ns := range joinNs {
parts := strings.Split(ns, ":")
if len(parts) != 2 {
nsType, nsPath, ok := strings.Cut(ns, ":")
if !ok {
return nil, errors.New("joining a Linux namespace using --with-ns requires the format 'nstype:path'")
}
if !validNamespace(parts[0]) {
return nil, errors.New("the Linux namespace type specified in --with-ns is not valid: " + parts[0])
if !validNamespace(nsType) {
return nil, errors.New("the Linux namespace type specified in --with-ns is not valid: " + nsType)
}
opts = append(opts, oci.WithLinuxNamespace(specs.LinuxNamespace{
Type: specs.LinuxNamespaceType(parts[0]),
Path: parts[1],
Type: specs.LinuxNamespaceType(nsType),
Path: nsPath,
}))
}
if context.IsSet("gpus") {
@@ -457,7 +457,8 @@ func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts {
}
func parseIDMapping(mapping string) (specs.LinuxIDMapping, error) {
parts := strings.Split(mapping, ":")
// We expect 3 parts, but limit to 4 to allow detection of invalid values.
parts := strings.SplitN(mapping, ":", 4)
if len(parts) != 3 {
return specs.LinuxIDMapping{}, errors.New("user namespace mappings require the format `container-id:host-id:size`")
}