From aaa40435f3b5c5684d2d0cb3b5aeae886209d487 Mon Sep 17 00:00:00 2001 From: vasayxtx Date: Wed, 9 Sep 2020 17:37:49 +0300 Subject: [PATCH] Add an ability to prepare pattern before glob It's needed for performance sensitive cases. --- glob.go | 57 +++++++++++++++++++++++++++++----------------------- glob_test.go | 10 +++++++++ 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/glob.go b/glob.go index e67db3b..0a01445 100644 --- a/glob.go +++ b/glob.go @@ -5,52 +5,59 @@ import "strings" // The character which is treated like a glob const GLOB = "*" -// Glob will test a string pattern, potentially containing globs, against a -// subject string. The result is a simple true/false, determining whether or -// not the glob pattern matched the subject text. -func Glob(pattern, subj string) bool { +// Compile will prepare a string pattern and return a function for further matching. +func Compile(pattern string) func(subj string) bool { // Empty pattern can only match empty subject if pattern == "" { - return subj == pattern + return func(subj string) bool { return subj == "" } } // If the pattern _is_ a glob, it matches everything if pattern == GLOB { - return true + return func(subj string) bool { return true } } parts := strings.Split(pattern, GLOB) if len(parts) == 1 { // No globs in pattern, so test for equality - return subj == pattern + return func(subj string) bool { return subj == pattern } } leadingGlob := strings.HasPrefix(pattern, GLOB) trailingGlob := strings.HasSuffix(pattern, GLOB) end := len(parts) - 1 - // Go over the leading parts and ensure they match. - for i := 0; i < end; i++ { - idx := strings.Index(subj, parts[i]) - - switch i { - case 0: - // Check the first section. Requires special handling. - if !leadingGlob && idx != 0 { - return false - } - default: - // Check that the middle parts match. - if idx < 0 { - return false + return func(subj string) bool { + // Go over the leading parts and ensure they match. + for i := 0; i < end; i++ { + idx := strings.Index(subj, parts[i]) + + switch i { + case 0: + // Check the first section. Requires special handling. + if !leadingGlob && idx != 0 { + return false + } + default: + // Check that the middle parts match. + if idx < 0 { + return false + } } + + // Trim evaluated text from subj as we loop over the pattern. + subj = subj[idx+len(parts[i]):] } - // Trim evaluated text from subj as we loop over the pattern. - subj = subj[idx+len(parts[i]):] + // Reached the last section. Requires special handling. + return trailingGlob || strings.HasSuffix(subj, parts[end]) } +} - // Reached the last section. Requires special handling. - return trailingGlob || strings.HasSuffix(subj, parts[end]) +// Glob will test a string pattern, potentially containing globs, against a +// subject string. The result is a simple true/false, determining whether or +// not the glob pattern matched the subject text. +func Glob(pattern, subj string) bool { + return Compile(pattern)(subj) } diff --git a/glob_test.go b/glob_test.go index fa4edee..8af8c86 100644 --- a/glob_test.go +++ b/glob_test.go @@ -103,3 +103,13 @@ func BenchmarkGlob(b *testing.B) { } } } + +func BenchmarkCompiledGlob(b *testing.B) { + compiledGlob := Compile("*quick*fox*dog") + b.ResetTimer() + for i := 0; i < b.N; i++ { + if !compiledGlob("The quick brown fox jumped over the lazy dog") { + b.Fatalf("should match") + } + } +}