Skip to content

Instantly share code, notes, and snippets.

@Dynom
Last active November 2, 2017 10:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Dynom/7da7f7cefb440f1dce29ba7b377d6f54 to your computer and use it in GitHub Desktop.
Save Dynom/7da7f7cefb440f1dce29ba7b377d6f54 to your computer and use it in GitHub Desktop.
package Random
import (
"strings"
"testing"
)
func BenchmarkSplitOrSuffixMatching(b *testing.B) {
const path = "/baz"
const test = "baz"
b.Run("Split", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = matchLastPathSegmentWithSplit(path, test)
}
})
b.Run("Suffix", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = matchLastPathSegmentWithSuffix(path, test)
}
})
}
func BenchmarkSplitOrSuffixMatchingBulk(b *testing.B) {
const requestPath = "/bar/b/a"
var paths = []string{
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
}
b.Run("Split", func(b *testing.B) {
for i := 0; i < b.N; i++ {
parts := strings.Split(requestPath, "/")
test := parts[len(parts)-1]
for _, p := range paths {
if p == test {
// true
} else {
// false
}
}
}
})
b.Run("Suffix", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, p := range paths {
if strings.HasSuffix(requestPath, p) {
// true
} else {
// false
}
}
}
})
var pathsMap = make(map[string]struct{}, len(paths))
for _, p := range paths {
pathsMap[p] = struct{}{}
}
b.Run("Map", func(b *testing.B) {
for i := 0; i < b.N; i++ {
parts := strings.Split(requestPath, "/")
test := parts[len(parts)-1]
if _, ok := pathsMap[test]; ok {
// true
} else {
// false
}
}
})
}
func TestBoth(t *testing.T) {
for _, td := range []struct {
path string
against string
}{
{path: "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z", against: ""},
{path: "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z", against: "no match"},
{path: "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/", against: "z"},
{path: "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z", against: "z/"},
{path: "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z", against: "z"},
{path: "/a/b/c", against: "/a/b/c"},
{path: "/a/b/c", against: "a/b/c"},
{path: "/a/b/0", against: "0"},
{path: "/a/b/^", against: "^"},
} {
a := matchLastPathSegmentWithSuffix(td.path, td.against)
b := matchLastPathSegmentWithSplit(td.path, td.against)
if a != b {
t.Errorf("Implementation missmatch\nSuffix: %+v\nSplit: %+v\n%+v", a, b, td)
}
}
}
func matchLastPathSegmentWithSplit(path, test string) bool {
parts := strings.Split(path, "/")
return parts[len(parts)-1] == test
}
func matchLastPathSegmentWithSuffix(path, test string) bool {
// Protect against incompatibility with the Split approach
if len(test) == 0 || strings.Count(test, "/") > 0 {
return false
}
return strings.HasSuffix(path, test)
}
/* go test -test.v -test.benchmem -test.bench ^.*$ split_or_suffix_test.go
=== RUN TestBoth
--- PASS: TestBoth (0.00s)
goos: darwin
goarch: amd64
BenchmarkSplitOrSuffixMatching/Split-4 10000000 123 ns/op 32 B/op 1 allocs/op
BenchmarkSplitOrSuffixMatching/Suffix-4 100000000 19.5 ns/op 0 B/op 0 allocs/op
BenchmarkSplitOrSuffixMatchingBulk/Split-4 5000000 340 ns/op 64 B/op 1 allocs/op
BenchmarkSplitOrSuffixMatchingBulk/Suffix-4 10000000 198 ns/op 0 B/op 0 allocs/op
BenchmarkSplitOrSuffixMatchingBulk/Map-4 10000000 188 ns/op 64 B/op 1 allocs/op
PASS
ok command-line-arguments 9.643s
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment