diff --git a/cmd/globdraw/main.go b/cmd/globdraw/main.go new file mode 100644 index 0000000..bc64020 --- /dev/null +++ b/cmd/globdraw/main.go @@ -0,0 +1,79 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "github.com/gobwas/glob" + "github.com/gobwas/glob/match" + "math/rand" + "os" + "strings" +) + +func draw(pattern string, m match.Matcher) string { + return fmt.Sprintf(`digraph G {graph[label="%s"];%s}`, pattern, graphviz(m, fmt.Sprintf("%x", rand.Int63()))) +} + +func graphviz(m match.Matcher, id string) string { + buf := &bytes.Buffer{} + + switch matcher := m.(type) { + case match.BTree: + fmt.Fprintf(buf, `"%s"[label="%s"];`, id, matcher.Value.String()) + for _, m := range []match.Matcher{matcher.Left, matcher.Right} { + switch n := m.(type) { + case nil: + rnd := rand.Int63() + fmt.Fprintf(buf, `"%x"[label=""];`, rnd) + fmt.Fprintf(buf, `"%s"->"%x";`, id, rnd) + + default: + sub := fmt.Sprintf("%x", rand.Int63()) + fmt.Fprintf(buf, `"%s"->"%s";`, id, sub) + fmt.Fprintf(buf, graphviz(n, sub)) + } + } + + case match.AnyOf: + fmt.Fprintf(buf, `"%s"[label="AnyOf"];`, id) + for _, m := range matcher.Matchers { + rnd := rand.Int63() + fmt.Fprintf(buf, graphviz(m, fmt.Sprintf("%x", rnd))) + fmt.Fprintf(buf, `"%s"->"%x";`, id, rnd) + } + + case match.EveryOf: + fmt.Fprintf(buf, `"%s"[label="EveryOf"];`, id) + for _, m := range matcher.Matchers { + rnd := rand.Int63() + fmt.Fprintf(buf, graphviz(m, fmt.Sprintf("%x", rnd))) + fmt.Fprintf(buf, `"%s"->"%x";`, id, rnd) + } + + default: + fmt.Fprintf(buf, `"%s"[label="%s"];`, id, m.String()) + } + + return buf.String() +} + +func main() { + pattern := flag.String("p", "", "pattern to draw") + sep := flag.String("s", "", "comma separated list of separators") + flag.Parse() + + if *pattern == "" { + flag.Usage() + os.Exit(1) + } + + glob, err := glob.Compile(*pattern, strings.Split(*sep, ",")...) + if err != nil { + fmt.Println("could not compile pattern:", err) + os.Exit(1) + } + + matcher := glob.(match.Matcher) + fmt.Fprint(os.Stdout, draw(*pattern, matcher)) +} diff --git a/cmd/globtest/main.go b/cmd/globtest/main.go new file mode 100644 index 0000000..25c89ca --- /dev/null +++ b/cmd/globtest/main.go @@ -0,0 +1,72 @@ +package main + +import ( + "flag" + "fmt" + "github.com/gobwas/glob" + "os" + "strings" + "testing" +) + +func benchString(r testing.BenchmarkResult) string { + nsop := r.NsPerOp() + ns := fmt.Sprintf("%10d ns/op", nsop) + allocs := "0" + if r.N > 0 { + if nsop < 100 { + // The format specifiers here make sure that + // the ones digits line up for all three possible formats. + if nsop < 10 { + ns = fmt.Sprintf("%13.2f ns/op", float64(r.T.Nanoseconds())/float64(r.N)) + } else { + ns = fmt.Sprintf("%12.1f ns/op", float64(r.T.Nanoseconds())/float64(r.N)) + } + } + + allocs = fmt.Sprintf("%d", r.MemAllocs/uint64(r.N)) + } + + return fmt.Sprintf("%8d\t%s\t%s allocs", r.N, ns, allocs) +} + +func main() { + pattern := flag.String("p", "", "pattern to draw") + sep := flag.String("s", "", "comma separated list of separators") + fixture := flag.String("f", "", "fixture") + verbose := flag.Bool("v", false, "verbose") + flag.Parse() + + if *pattern == "" { + flag.Usage() + os.Exit(1) + } + + separators := strings.Split(*sep, ",") + g, err := glob.Compile(*pattern, separators...) + if err != nil { + fmt.Println("could not compile pattern:", err) + os.Exit(1) + } + + if !*verbose { + fmt.Println(g.Match(*fixture)) + return + } + + fmt.Printf("result: %t\n", g.Match(*fixture)) + + cb := testing.Benchmark(func(b *testing.B) { + for i := 0; i < b.N; i++ { + glob.Compile(*pattern, separators...) + } + }) + fmt.Println("compile:", benchString(cb)) + + mb := testing.Benchmark(func(b *testing.B) { + for i := 0; i < b.N; i++ { + g.Match(*fixture) + } + }) + fmt.Println("match: ", benchString(mb)) +} diff --git a/util.go b/util.go deleted file mode 100644 index 0423e91..0000000 --- a/util.go +++ /dev/null @@ -1,22 +0,0 @@ -package glob - -import ( - "strings" -) - -func indexByteNonEscaped(source string, needle, escape byte, shift int) int { - i := strings.IndexByte(source, needle) - if i == -1 { - return -1 - } - if i == 0 { - return shift - } - - if source[i-1] != escape { - return i + shift - } - - sh := i + 1 - return indexByteNonEscaped(source[sh:], needle, escape, sh) -}