glob/match/segments.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
}
}