forked from mirror/gin
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:
parent
1d5b9badd9
commit
b4c8bf1bbe
45
tree.go
45
tree.go
|
@ -5,10 +5,18 @@
|
||||||
package gin
|
package gin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
strColon = []byte(":")
|
||||||
|
strStar = []byte("*")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Param is a single URL parameter, consisting of a key and a value.
|
// 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
|
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 {
|
func countParams(path string) uint16 {
|
||||||
var n uint
|
var n uint
|
||||||
for i := range []byte(path) {
|
s := strToBytes(path)
|
||||||
switch path[i] {
|
n += uint(bytes.Count(s, strColon))
|
||||||
case ':', '*':
|
n += uint(bytes.Count(s, strStar))
|
||||||
n++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return uint16(n)
|
return uint16(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +192,7 @@ walk:
|
||||||
|
|
||||||
n.children = []*node{&child}
|
n.children = []*node{&child}
|
||||||
// []byte for proper unicode char conversion, see #65
|
// []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.path = path[:i]
|
||||||
n.handlers = nil
|
n.handlers = nil
|
||||||
n.wildChild = false
|
n.wildChild = false
|
||||||
|
@ -223,7 +252,7 @@ walk:
|
||||||
// Otherwise insert it
|
// Otherwise insert it
|
||||||
if c != ':' && c != '*' {
|
if c != ':' && c != '*' {
|
||||||
// []byte for proper unicode char conversion, see #65
|
// []byte for proper unicode char conversion, see #65
|
||||||
n.indices += string([]byte{c})
|
n.indices += bytesToStr([]byte{c})
|
||||||
child := &node{
|
child := &node{
|
||||||
fullPath: fullPath,
|
fullPath: fullPath,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue