Skip to content

Commit 4b96cc2

Browse files
committed
perf: optimize KeyMatch functions with fast path for wildcard replacement
This change introduces a fast path optimization for KeyMatch2, KeyMatch3, KeyMatch4, KeyMatch5 and their corresponding KeyGet functions. Original code (unconditional replacement): key2 = strings.Replace(key2, "/*", "/.*", -1) Optimized code (conditional replacement): if strings.Contains(key2, "/*") { //nolint:gosimple // optimization key2 = strings.Replace(key2, "/*", "/.*", -1) } This avoids unnecessary allocations and processing when the key does not contain a wildcard, as verified by upstream benchmarks using test data like 'examples/performance/rbac_with_pattern_large_scale_policy.csv'.
1 parent 0fe9505 commit 4b96cc2

File tree

1 file changed

+18
-6
lines changed

1 file changed

+18
-6
lines changed

util/builtin_operators.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ func KeyGetFunc(args ...interface{}) (interface{}, error) {
137137
// KeyMatch2 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
138138
// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/:resource".
139139
func KeyMatch2(key1 string, key2 string) bool {
140-
key2 = strings.Replace(key2, "/*", "/.*", -1)
140+
if strings.Contains(key2, "/*") { //nolint:gosimple // optimization
141+
key2 = strings.Replace(key2, "/*", "/.*", -1)
142+
}
141143

142144
key2 = keyMatch2Re.ReplaceAllString(key2, "$1[^/]+$2")
143145

@@ -160,7 +162,9 @@ func KeyMatch2Func(args ...interface{}) (interface{}, error) {
160162
// For example, "/resource1" matches "/:resource"
161163
// if the pathVar == "resource", then "resource1" will be returned.
162164
func KeyGet2(key1, key2 string, pathVar string) string {
163-
key2 = strings.Replace(key2, "/*", "/.*", -1)
165+
if strings.Contains(key2, "/*") { //nolint:gosimple // optimization
166+
key2 = strings.Replace(key2, "/*", "/.*", -1)
167+
}
164168
keys := keyGet2Re1.FindAllString(key2, -1)
165169
key2 = keyGet2Re1.ReplaceAllString(key2, "$1([^/]+)$2")
166170
key2 = "^" + key2 + "$"
@@ -194,7 +198,9 @@ func KeyGet2Func(args ...interface{}) (interface{}, error) {
194198
// KeyMatch3 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
195199
// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}".
196200
func KeyMatch3(key1 string, key2 string) bool {
197-
key2 = strings.Replace(key2, "/*", "/.*", -1)
201+
if strings.Contains(key2, "/*") { //nolint:gosimple // optimization
202+
key2 = strings.Replace(key2, "/*", "/.*", -1)
203+
}
198204
key2 = keyMatch3Re.ReplaceAllString(key2, "$1[^/]+$2")
199205

200206
return RegexMatch(key1, "^"+key2+"$")
@@ -216,7 +222,9 @@ func KeyMatch3Func(args ...interface{}) (interface{}, error) {
216222
// For example, "project/proj_project1_admin/" matches "project/proj_{project}_admin/"
217223
// if the pathVar == "project", then "project1" will be returned.
218224
func KeyGet3(key1, key2 string, pathVar string) string {
219-
key2 = strings.Replace(key2, "/*", "/.*", -1)
225+
if strings.Contains(key2, "/*") { //nolint:gosimple // optimization
226+
key2 = strings.Replace(key2, "/*", "/.*", -1)
227+
}
220228

221229
keys := keyGet3Re1.FindAllString(key2, -1)
222230
key2 = keyGet3Re1.ReplaceAllString(key2, "$1([^/]+?)$2")
@@ -253,7 +261,9 @@ func KeyGet3Func(args ...interface{}) (interface{}, error) {
253261
// "/parent/123/child/456" does not match "/parent/{id}/child/{id}"
254262
// But KeyMatch3 will match both.
255263
func KeyMatch4(key1 string, key2 string) bool {
256-
key2 = strings.Replace(key2, "/*", "/.*", -1)
264+
if strings.Contains(key2, "/*") { //nolint:gosimple // optimization
265+
key2 = strings.Replace(key2, "/*", "/.*", -1)
266+
}
257267

258268
tokens := []string{}
259269

@@ -312,7 +322,9 @@ func KeyMatch5(key1 string, key2 string) bool {
312322
key1 = key1[:i]
313323
}
314324

315-
key2 = strings.Replace(key2, "/*", "/.*", -1)
325+
if strings.Contains(key2, "/*") { //nolint:gosimple // optimization
326+
key2 = strings.Replace(key2, "/*", "/.*", -1)
327+
}
316328
key2 = keyMatch5Re.ReplaceAllString(key2, "$1[^/]+$2")
317329

318330
return RegexMatch(key1, "^"+key2+"$")

0 commit comments

Comments
 (0)