From 8467ce7abc9c39dcb05f260a1934cbe184e05f4c Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Sun, 17 May 2020 15:24:08 +0800 Subject: [PATCH] chore: improve countParams performance --- tree.go | 35 +++++++++++++++++++++++++---------- tree_test.go | 14 ++++++++++++++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/tree.go b/tree.go index 24f14060..2e0c4478 100644 --- a/tree.go +++ b/tree.go @@ -5,13 +5,20 @@ package gin import ( + "bytes" "net/url" + "reflect" "strings" "unicode" "unicode/utf8" "unsafe" ) +var ( + strColon = []byte(":") + strStar = []byte("*") +) + // Param is a single URL parameter, consisting of a key and a value. type Param struct { Key string @@ -41,10 +48,6 @@ func (ps Params) ByName(name string) (va string) { return } -func bytesToStr(b []byte) string { - return *(*string)(unsafe.Pointer(&b)) -} - type methodTree struct { method string root *node @@ -77,14 +80,26 @@ func longestCommonPrefix(a, b string) int { return i } +func bytesToStr(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +func strToBytes(s string) (b []byte) { + /* #nosec G103 */ + bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + /* #nosec G103 */ + sh := *(*reflect.StringHeader)(unsafe.Pointer(&s)) + bh.Data = sh.Data + bh.Len = sh.Len + bh.Cap = sh.Len + return b +} + func countParams(path string) uint16 { var n uint - for i := range []byte(path) { - switch path[i] { - case ':', '*': - n++ - } - } + s := strToBytes(path) + n += uint(bytes.Count(s, strColon)) + n += uint(bytes.Count(s, strStar)) return uint16(n) } diff --git a/tree_test.go b/tree_test.go index 1cb4f559..e244e140 100644 --- a/tree_test.go +++ b/tree_test.go @@ -93,6 +93,20 @@ func TestCountParams(t *testing.T) { } } +var s = strings.Repeat("/:param", 5) + +func BenchmarkCountParamsOld(b *testing.B) { + for i := 0; i < b.N; i++ { + countParamsOld(s) + } +} + +func BenchmarkCountParams(b *testing.B) { + for i := 0; i < b.N; i++ { + countParamsNew(s) + } +} + func TestTreeAddAndGet(t *testing.T) { tree := &node{}