chore(performance): improve countParams (#2378)

* update

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* chore: update

* chore: improve countParams performance

* update

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* chore: add comment
This commit is contained in:
Bo-Yi Wu 2020-05-17 18:11:22 +08:00 committed by GitHub
parent 1d5b9badd9
commit b4c8bf1bbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

45
tree.go
View File

@ -5,10 +5,18 @@
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.
@ -72,14 +80,35 @@ func longestCommonPrefix(a, b string) int {
return i
}
// bytesToStr converts byte slice to a string without memory allocation.
// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
//
// Note it may break if string and/or slice header will change
// in the future go versions.
func bytesToStr(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
// strToBytes converts string to a byte slice without memory allocation.
//
// Note it may break if string and/or slice header will change
// in the future go versions.
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)
}
@ -163,7 +192,7 @@ walk:
n.children = []*node{&child}
// []byte for proper unicode char conversion, see #65
n.indices = string([]byte{n.path[i]})
n.indices = bytesToStr([]byte{n.path[i]})
n.path = path[:i]
n.handlers = nil
n.wildChild = false
@ -223,7 +252,7 @@ walk:
// Otherwise insert it
if c != ':' && c != '*' {
// []byte for proper unicode char conversion, see #65
n.indices += string([]byte{c})
n.indices += bytesToStr([]byte{c})
child := &node{
fullPath: fullPath,
}