forked from mirror/glob
200 lines
3.1 KiB
Go
200 lines
3.1 KiB
Go
package match
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
const lenOne = 1
|
|
const lenZero = 0
|
|
const lenNo = -1
|
|
|
|
type Matcher interface {
|
|
Match(string) bool
|
|
Index(string, []int) (int, []int)
|
|
Len() int
|
|
String() string
|
|
}
|
|
|
|
type Matchers []Matcher
|
|
|
|
func (m Matchers) String() string {
|
|
var s []string
|
|
for _, matcher := range m {
|
|
s = append(s, fmt.Sprint(matcher))
|
|
}
|
|
|
|
return fmt.Sprintf("%s", strings.Join(s, ","))
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func init() {
|
|
for i := 1024; i >= 1; i >>= 1 {
|
|
func(i int) {
|
|
segmentsPools[i-1] = sync.Pool{
|
|
New: func() interface{} {
|
|
return make([]int, 0, i)
|
|
},
|
|
}
|
|
}(i)
|
|
}
|
|
}
|
|
|
|
var segmentsPool = sync.Pool{
|
|
New: func() interface{} {
|
|
return make([]int, 0, 64)
|
|
},
|
|
}
|
|
|
|
func getIdx(c int) int {
|
|
p := toPowerOfTwo(c)
|
|
switch {
|
|
case p >= 1024:
|
|
return 1023
|
|
case p < 1:
|
|
return 0
|
|
default:
|
|
return p - 1
|
|
}
|
|
}
|
|
|
|
func acquireSegments(c int) []int {
|
|
return segmentsPools[getIdx(c)].Get().([]int)[:0]
|
|
}
|
|
|
|
func releaseSegments(s []int) {
|
|
segmentsPools[getIdx(cap(s))].Put(s)
|
|
}
|
|
|
|
func appendIfNotAsPrevious(target []int, val int) []int {
|
|
l := len(target)
|
|
if l != 0 && target[l-1] == val {
|
|
return target
|
|
}
|
|
|
|
return append(target, val)
|
|
}
|
|
|
|
func appendMerge(target, sub []int) []int {
|
|
lt, ls := len(target), len(sub)
|
|
out := acquireSegments(lt + ls)
|
|
|
|
for x, y := 0, 0; x < lt || y < ls; {
|
|
if x >= lt {
|
|
out = append(out, sub[y:]...)
|
|
break
|
|
}
|
|
|
|
if y >= ls {
|
|
out = append(out, target[x:]...)
|
|
break
|
|
}
|
|
|
|
xValue := target[x]
|
|
yValue := sub[y]
|
|
|
|
switch {
|
|
|
|
case xValue == yValue:
|
|
out = append(out, xValue)
|
|
x++
|
|
y++
|
|
|
|
case xValue < yValue:
|
|
out = append(out, xValue)
|
|
x++
|
|
|
|
case yValue < xValue:
|
|
out = append(out, yValue)
|
|
y++
|
|
|
|
}
|
|
}
|
|
|
|
target = append(target[:0], out...)
|
|
releaseSegments(out)
|
|
|
|
return target
|
|
}
|
|
|
|
// mergeSegments merges and sorts given already SORTED and UNIQUE segments.
|
|
func mergeSegments(list [][]int, out []int) []int {
|
|
var current []int
|
|
switch len(list) {
|
|
case 0:
|
|
return out
|
|
case 1:
|
|
return list[0]
|
|
default:
|
|
current = acquireSegments(len(list[0]))
|
|
current = append(current, list[0]...)
|
|
// releaseSegments(list[0])
|
|
}
|
|
|
|
for _, s := range list[1:] {
|
|
next := acquireSegments(len(current) + len(s))
|
|
for x, y := 0, 0; x < len(current) || y < len(s); {
|
|
if x >= len(current) {
|
|
next = append(next, s[y:]...)
|
|
break
|
|
}
|
|
|
|
if y >= len(s) {
|
|
next = append(next, current[x:]...)
|
|
break
|
|
}
|
|
|
|
xValue := current[x]
|
|
yValue := s[y]
|
|
|
|
switch {
|
|
|
|
case xValue == yValue:
|
|
x++
|
|
y++
|
|
next = appendIfNotAsPrevious(next, xValue)
|
|
|
|
case xValue < yValue:
|
|
next = appendIfNotAsPrevious(next, xValue)
|
|
x++
|
|
|
|
case yValue < xValue:
|
|
next = appendIfNotAsPrevious(next, yValue)
|
|
y++
|
|
|
|
}
|
|
}
|
|
|
|
releaseSegments(current)
|
|
current = next
|
|
}
|
|
|
|
out = append(out, current...)
|
|
releaseSegments(current)
|
|
|
|
return out
|
|
}
|
|
|
|
func reverseSegments(input []int) {
|
|
l := len(input)
|
|
m := l / 2
|
|
|
|
for i := 0; i < m; i++ {
|
|
input[i], input[l-i-1] = input[l-i-1], input[i]
|
|
}
|
|
}
|