topdown: fix split(..., "")

Fixes https://github.com/open-policy-agent/opa/issues/8018

goos: darwin
goarch: arm64
pkg: github.com/open-policy-agent/opa/v1/topdown
cpu: Apple M4 Max
                                        │ main.bench  │               pr.bench               │
                                        │   sec/op    │   sec/op     vs base                 │
Split-16                                  238.7n ± 1%   254.2n ± 1%  +6.47% (p=0.000 n=10)

                                        │  main.bench  │              pr.bench               │
                                        │     B/op     │    B/op     vs base                 │
Split-16                                  384.0 ± 0%     384.0 ± 0%       ~ (p=1.000 n=10) ¹
¹ all samples are equal

                                        │  main.bench  │              pr.bench               │
                                        │  allocs/op   │ allocs/op   vs base                 │
Split-16                                  14.00 ± 0%     14.00 ± 0%       ~ (p=1.000 n=10) ¹
¹ all samples are equal

Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
This commit is contained in:
Stephan Renatus
2025-11-05 09:14:44 +01:00
parent e6865c4c9f
commit d1d5a84387
2 changed files with 22 additions and 11 deletions
+19 -1
View File
@@ -1,6 +1,6 @@
---
cases:
- note: "strings/split: empty string"
- note: "strings/split: empty text string"
query: data.generated.p = x
modules:
- |
@@ -12,3 +12,21 @@ cases:
data: {}
want_result:
- x: ""
- note: "strings/split: empty delim string"
query: data.test.p = x
modules:
- |
package test
p := split("test", "")
want_result:
- x: [t, e, s, t]
- note: "strings/split: empty text and delim string"
query: data.test.p = x
modules:
- |
package test
p := split("", "")
want_result:
- x: []
+3 -10
View File
@@ -79,17 +79,10 @@ func KeysCount[K comparable, V any](m map[K]V, p func(K) bool) int {
// SplitMap calls fn for each delim-separated part of text and returns a slice of the results.
// Cheaper than calling fn on strings.Split(text, delim), as it avoids allocating an intermediate slice of strings.
func SplitMap[T any](text string, delim string, fn func(string) T) []T {
before, after, found := strings.Cut(text, delim)
if !found {
return []T{fn(text)}
sl := make([]T, 0, strings.Count(text, delim)+1)
for s := range strings.SplitSeq(text, delim) {
sl = append(sl, fn(s))
}
sl := append(make([]T, 0, strings.Count(text, delim)+1), fn(before))
for found {
before, after, found = strings.Cut(after, delim)
sl = append(sl, fn(before))
}
return sl
}