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

@@ -141,10 +141,10 @@ func checkContainerLog(t *testing.T, log string, messages []string) {
lines := strings.Split(strings.TrimSpace(log), "\n")
require.Len(t, lines, len(messages), "log line number should match")
for i, line := range lines {
parts := strings.SplitN(line, " ", 2)
require.Len(t, parts, 2)
_, err := time.Parse(time.RFC3339Nano, parts[0])
ts, msg, ok := strings.Cut(line, " ")
require.True(t, ok)
_, err := time.Parse(time.RFC3339Nano, ts)
assert.NoError(t, err, "timestamp should be in RFC3339Nano format")
assert.Equal(t, messages[i], parts[1], "log content should match")
assert.Equal(t, messages[i], msg, "log content should match")
}
}

View File

@@ -509,14 +509,14 @@ func PidEnvs(pid int) (map[string]string, error) {
res := make(map[string]string)
for _, value := range values {
value := strings.TrimSpace(string(value))
value = bytes.TrimSpace(value)
if len(value) == 0 {
continue
}
parts := strings.SplitN(value, "=", 2)
if len(parts) == 2 {
res[parts[0]] = parts[1]
k, v, ok := strings.Cut(string(value), "=")
if ok {
res[k] = v
}
}
return res, nil

View File

@@ -349,12 +349,7 @@ func ensureCNIAddRunning(t *testing.T, sbName string) error {
}
for _, arg := range strings.Split(args, ";") {
kv := strings.SplitN(arg, "=", 2)
if len(kv) != 2 {
continue
}
if kv[0] == "K8S_POD_NAME" && kv[1] == sbName {
if arg == "K8S_POD_NAME="+sbName {
return true, nil
}
}