mirror of https://github.com/gobwas/glob.git
162 lines
2.5 KiB
Go
162 lines
2.5 KiB
Go
package match
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
type SomePool interface {
|
|
Get() []int
|
|
Put([]int)
|
|
}
|
|
|
|
var segmentsPools [1024]SomePool
|
|
|
|
//var segmentsPools [1024]*sync.Pool
|
|
|
|
func toPowerOfTwo(v int) int {
|
|
v--
|
|
v |= v >> 1
|
|
v |= v >> 2
|
|
v |= v >> 4
|
|
v |= v >> 8
|
|
v |= v >> 16
|
|
v++
|
|
|
|
return v
|
|
}
|
|
|
|
const (
|
|
cacheFrom = 16
|
|
cacheToAndHigher = 1024
|
|
cacheFromIndex = 15
|
|
cacheToAndHigherIndex = 1023
|
|
)
|
|
|
|
var (
|
|
segments0 = []int{0}
|
|
segments1 = []int{1}
|
|
segments2 = []int{2}
|
|
segments3 = []int{3}
|
|
segments4 = []int{4}
|
|
)
|
|
|
|
var segmentsByRuneLength [5][]int = [5][]int{
|
|
0: segments0,
|
|
1: segments1,
|
|
2: segments2,
|
|
3: segments3,
|
|
4: segments4,
|
|
}
|
|
|
|
const (
|
|
asciiLo = 0
|
|
asciiHi = 127
|
|
)
|
|
|
|
func init() {
|
|
for i := cacheToAndHigher; i >= cacheFrom; i >>= 1 {
|
|
func(i int) {
|
|
// segmentsPools[i-1] = &sync.Pool{New: func() interface{} {
|
|
// return make([]int, 0, i)
|
|
// }}
|
|
// segmentsPools[i-1] = newChanPool(func() []int {
|
|
// return make([]int, 0, i)
|
|
// })
|
|
segmentsPools[i-1] = newSyncPool(func() []int {
|
|
return make([]int, 0, i)
|
|
})
|
|
}(i)
|
|
}
|
|
}
|
|
|
|
func getTableIndex(c int) int {
|
|
p := toPowerOfTwo(c)
|
|
switch {
|
|
case p >= cacheToAndHigher:
|
|
return cacheToAndHigherIndex
|
|
case p <= cacheFrom:
|
|
return cacheFromIndex
|
|
default:
|
|
return p - 1
|
|
}
|
|
}
|
|
|
|
func acquireSegments(c int) []int {
|
|
// make []int with less capacity than cacheFrom
|
|
// is faster than acquiring it from pool
|
|
if c < cacheFrom {
|
|
return make([]int, 0, c)
|
|
}
|
|
|
|
// return segmentsPools[getTableIndex(c)].Get().([]int)[:0]
|
|
return segmentsPools[getTableIndex(c)].Get()
|
|
}
|
|
|
|
func releaseSegments(s []int) {
|
|
c := cap(s)
|
|
|
|
// make []int with less capacity than cacheFrom
|
|
// is faster than acquiring it from pool
|
|
if c < cacheFrom {
|
|
return
|
|
}
|
|
|
|
segmentsPools[getTableIndex(c)].Put(s)
|
|
}
|
|
|
|
type maker func() []int
|
|
|
|
type syncPool struct {
|
|
new maker
|
|
pool sync.Pool
|
|
}
|
|
|
|
func newSyncPool(m maker) *syncPool {
|
|
return &syncPool{
|
|
new: m,
|
|
pool: sync.Pool{New: func() interface{} {
|
|
return m()
|
|
}},
|
|
}
|
|
}
|
|
|
|
func (s *syncPool) Get() []int {
|
|
return s.pool.Get().([]int)[:0]
|
|
}
|
|
|
|
func (s *syncPool) Put(x []int) {
|
|
s.pool.Put(x)
|
|
}
|
|
|
|
type chanPool struct {
|
|
pool chan []int
|
|
new maker
|
|
index int
|
|
}
|
|
|
|
func newChanPool(m maker) *chanPool {
|
|
return &chanPool{
|
|
pool: make(chan []int, 16),
|
|
new: m,
|
|
}
|
|
}
|
|
|
|
func (c *chanPool) Get() []int {
|
|
select {
|
|
case s := <-c.pool:
|
|
return s[:0]
|
|
default:
|
|
// pool is empty
|
|
return c.new()
|
|
}
|
|
}
|
|
|
|
func (c *chanPool) Put(s []int) {
|
|
select {
|
|
case c.pool <- s:
|
|
// ok
|
|
default:
|
|
// pool is full
|
|
}
|
|
}
|