forked from mirror/glob
Compare commits
14 Commits
master
...
optimize-n
Author | SHA1 | Date |
---|---|---|
gobwas | 88b0fce4f5 | |
gobwas | ea3a6f712d | |
gobwas | 6cb2c11fd7 | |
gobwas | 291b8084ed | |
gobwas | be21acf93c | |
gobwas | 205c640a14 | |
gobwas | 35629e8ad6 | |
gobwas | bff71ed368 | |
gobwas | 54004631f5 | |
gobwas | 9b07f114a0 | |
gobwas | 325689ef4a | |
gobwas | 99cf82455b | |
gobwas | 9c0c7cba85 | |
gobwas | 0c30789d3a |
|
@ -1,64 +1,16 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
"github.com/gobwas/glob/match"
|
"github.com/gobwas/glob/match"
|
||||||
"math/rand"
|
"github.com/gobwas/glob/match/debug"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
func draw(pattern string, m match.Matcher) string {
|
|
||||||
return fmt.Sprintf(`digraph G {graph[label="%s"];%s}`, pattern, graphviz(m, fmt.Sprintf("%x", rand.Int63())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func graphviz(m match.Matcher, id string) string {
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
switch matcher := m.(type) {
|
|
||||||
case match.BTree:
|
|
||||||
fmt.Fprintf(buf, `"%s"[label="%s"];`, id, matcher.Value.String())
|
|
||||||
for _, m := range []match.Matcher{matcher.Left, matcher.Right} {
|
|
||||||
switch n := m.(type) {
|
|
||||||
case nil:
|
|
||||||
rnd := rand.Int63()
|
|
||||||
fmt.Fprintf(buf, `"%x"[label="<nil>"];`, rnd)
|
|
||||||
fmt.Fprintf(buf, `"%s"->"%x";`, id, rnd)
|
|
||||||
|
|
||||||
default:
|
|
||||||
sub := fmt.Sprintf("%x", rand.Int63())
|
|
||||||
fmt.Fprintf(buf, `"%s"->"%s";`, id, sub)
|
|
||||||
fmt.Fprintf(buf, graphviz(n, sub))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case match.AnyOf:
|
|
||||||
fmt.Fprintf(buf, `"%s"[label="AnyOf"];`, id)
|
|
||||||
for _, m := range matcher.Matchers {
|
|
||||||
rnd := rand.Int63()
|
|
||||||
fmt.Fprintf(buf, graphviz(m, fmt.Sprintf("%x", rnd)))
|
|
||||||
fmt.Fprintf(buf, `"%s"->"%x";`, id, rnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
case match.EveryOf:
|
|
||||||
fmt.Fprintf(buf, `"%s"[label="EveryOf"];`, id)
|
|
||||||
for _, m := range matcher.Matchers {
|
|
||||||
rnd := rand.Int63()
|
|
||||||
fmt.Fprintf(buf, graphviz(m, fmt.Sprintf("%x", rnd)))
|
|
||||||
fmt.Fprintf(buf, `"%s"->"%x";`, id, rnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
fmt.Fprintf(buf, `"%s"[label="%s"];`, id, m.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
pattern := flag.String("p", "", "pattern to draw")
|
pattern := flag.String("p", "", "pattern to draw")
|
||||||
sep := flag.String("s", "", "comma separated list of separators characters")
|
sep := flag.String("s", "", "comma separated list of separators characters")
|
||||||
|
@ -70,12 +22,14 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var separators []rune
|
var separators []rune
|
||||||
for _, c := range strings.Split(*sep, ",") {
|
if len(*sep) > 0 {
|
||||||
if r, w := utf8.DecodeRuneInString(c); len(c) > w {
|
for _, c := range strings.Split(*sep, ",") {
|
||||||
fmt.Println("only single charactered separators are allowed")
|
if r, w := utf8.DecodeRuneInString(c); len(c) > w {
|
||||||
os.Exit(1)
|
fmt.Println("only single charactered separators are allowed")
|
||||||
} else {
|
os.Exit(1)
|
||||||
separators = append(separators, r)
|
} else {
|
||||||
|
separators = append(separators, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,5 +40,5 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher := glob.(match.Matcher)
|
matcher := glob.(match.Matcher)
|
||||||
fmt.Fprint(os.Stdout, draw(*pattern, matcher))
|
fmt.Fprint(os.Stdout, debug.Graphviz(*pattern, matcher))
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ func (self Any) Index(s string, segments []int) (int, []int) {
|
||||||
switch found {
|
switch found {
|
||||||
case -1:
|
case -1:
|
||||||
case 0:
|
case 0:
|
||||||
segments = append(segments)
|
|
||||||
return 0, segments
|
return 0, segments
|
||||||
default:
|
default:
|
||||||
s = s[:found]
|
s = s[:found]
|
||||||
|
@ -27,7 +26,6 @@ func (self Any) Index(s string, segments []int) (int, []int) {
|
||||||
for i := range s {
|
for i := range s {
|
||||||
segments = append(segments, i)
|
segments = append(segments, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
segments = append(segments, len(s))
|
segments = append(segments, len(s))
|
||||||
|
|
||||||
return 0, segments
|
return 0, segments
|
||||||
|
@ -38,5 +36,5 @@ func (self Any) Len() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Any) String() string {
|
func (self Any) String() string {
|
||||||
return fmt.Sprintf("<any:![%s]>", self.Separators)
|
return fmt.Sprintf("<any:![%s]>", string(self.Separators))
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,14 @@ func (self AnyOf) Index(s string, segments []int) (int, []int) {
|
||||||
index := -1
|
index := -1
|
||||||
|
|
||||||
// create reusable segments
|
// create reusable segments
|
||||||
in := make([]int, 0, len(s))
|
// seg := acquireSegments(len(s))
|
||||||
|
// defer func() {
|
||||||
|
// releaseSegments(seg)
|
||||||
|
// }()
|
||||||
|
var seg []int
|
||||||
|
|
||||||
for _, m := range self.Matchers {
|
for _, m := range self.Matchers {
|
||||||
idx, seg := m.Index(s, in[:0])
|
idx, seg := m.Index(s, seg[:0])
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,10 @@ func TestAnyIndex(t *testing.T) {
|
||||||
|
|
||||||
func BenchmarkIndexAny(b *testing.B) {
|
func BenchmarkIndexAny(b *testing.B) {
|
||||||
m := Any{bench_separators}
|
m := Any{bench_separators}
|
||||||
|
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func BenchmarkIndexAnyParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,13 +77,21 @@ func (self BTree) Match(s string) bool {
|
||||||
limit = inputLen
|
limit = inputLen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if offset >= limit {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// reusable segments list
|
// reusable segments list
|
||||||
// inputLen is the maximum size of output segments values
|
// inputLen is the maximum size of output segments values
|
||||||
in := make([]int, 0, inputLen)
|
segments := acquireSegments(inputLen)
|
||||||
|
defer func() {
|
||||||
|
releaseSegments(segments)
|
||||||
|
}()
|
||||||
|
// segments := make([]int, 0, 4)
|
||||||
|
|
||||||
for offset < limit {
|
for offset < limit {
|
||||||
// search for matching part in substring
|
// search for matching part in substring
|
||||||
index, segments := self.Value.Index(s[offset:limit], in[:0])
|
index, segments := self.Value.Index(s[offset:limit], segments[:0])
|
||||||
if index == -1 {
|
if index == -1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,3 +46,44 @@ func TestBTree(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeMatcher struct {
|
||||||
|
len int
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeMatcher) Match(string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = 3
|
||||||
|
|
||||||
|
func (f *fakeMatcher) Index(s string, seg []int) (int, []int) {
|
||||||
|
for x := 0; x < i; x++ {
|
||||||
|
seg = append(seg, x)
|
||||||
|
}
|
||||||
|
return 0, seg
|
||||||
|
}
|
||||||
|
func (f *fakeMatcher) Len() int {
|
||||||
|
return f.len
|
||||||
|
}
|
||||||
|
func (f *fakeMatcher) String() string {
|
||||||
|
return f.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMatchBTree(b *testing.B) {
|
||||||
|
l := &fakeMatcher{4, "left_fake"}
|
||||||
|
r := &fakeMatcher{4, "right_fake"}
|
||||||
|
v := &fakeMatcher{2, "value_fake"}
|
||||||
|
|
||||||
|
// must be <= len(l + r + v)
|
||||||
|
fixture := "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"
|
||||||
|
|
||||||
|
bt := NewBTree(v, l, r)
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
bt.Match(fixture)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ func BenchmarkIndexContains(b *testing.B) {
|
||||||
|
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ func BenchmarkIndexContainsParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package debug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gobwas/glob/match"
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Graphviz(pattern string, m match.Matcher) string {
|
||||||
|
return fmt.Sprintf(`digraph G {graph[label="%s"];%s}`, pattern, matcherToGraphvizNode(m, fmt.Sprintf("%x", rand.Int63())))
|
||||||
|
}
|
||||||
|
|
||||||
|
func matcherToGraphvizNode(m match.Matcher, id string) string {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
switch matcher := m.(type) {
|
||||||
|
case match.BTree:
|
||||||
|
fmt.Fprintf(buf, `"%s"[label="%s"];`, id, matcher.Value.String())
|
||||||
|
for _, m := range []match.Matcher{matcher.Left, matcher.Right} {
|
||||||
|
switch n := m.(type) {
|
||||||
|
case nil:
|
||||||
|
rnd := rand.Int63()
|
||||||
|
fmt.Fprintf(buf, `"%x"[label="<nil>"];`, rnd)
|
||||||
|
fmt.Fprintf(buf, `"%s"->"%x";`, id, rnd)
|
||||||
|
|
||||||
|
default:
|
||||||
|
sub := fmt.Sprintf("%x", rand.Int63())
|
||||||
|
fmt.Fprintf(buf, `"%s"->"%s";`, id, sub)
|
||||||
|
fmt.Fprintf(buf, matcherToGraphvizNode(n, sub))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case match.AnyOf:
|
||||||
|
fmt.Fprintf(buf, `"%s"[label="AnyOf"];`, id)
|
||||||
|
for _, m := range matcher.Matchers {
|
||||||
|
rnd := rand.Int63()
|
||||||
|
fmt.Fprintf(buf, matcherToGraphvizNode(m, fmt.Sprintf("%x", rnd)))
|
||||||
|
fmt.Fprintf(buf, `"%s"->"%x";`, id, rnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
case match.EveryOf:
|
||||||
|
fmt.Fprintf(buf, `"%s"[label="EveryOf"];`, id)
|
||||||
|
for _, m := range matcher.Matchers {
|
||||||
|
rnd := rand.Int63()
|
||||||
|
fmt.Fprintf(buf, matcherToGraphvizNode(m, fmt.Sprintf("%x", rnd)))
|
||||||
|
fmt.Fprintf(buf, `"%s"->"%x";`, id, rnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(buf, `"%s"[label="%s"];`, id, m.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
|
@ -31,13 +31,24 @@ func (self EveryOf) Index(s string, out []int) (int, []int) {
|
||||||
|
|
||||||
// make `in` with cap as len(s),
|
// make `in` with cap as len(s),
|
||||||
// cause it is the maximum size of output segments values
|
// cause it is the maximum size of output segments values
|
||||||
in := make([]int, 0, len(s))
|
// seg := acquireSegments(len(s))
|
||||||
next := make([]int, 0, len(s))
|
// next := acquireSegments(len(s))
|
||||||
current := make([]int, 0, len(s))
|
// current := acquireSegments(len(s))
|
||||||
|
// defer func() {
|
||||||
|
// releaseSegments(seg)
|
||||||
|
// releaseSegments(next)
|
||||||
|
// releaseSegments(current)
|
||||||
|
// }()
|
||||||
|
var (
|
||||||
|
seg []int
|
||||||
|
next []int
|
||||||
|
current []int
|
||||||
|
)
|
||||||
|
|
||||||
sub := s
|
sub := s
|
||||||
for i, m := range self.Matchers {
|
for i, m := range self.Matchers {
|
||||||
idx, seg := m.Index(sub, in[:0])
|
var idx int
|
||||||
|
idx, seg = m.Index(sub, seg[:0])
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
return -1, nil
|
return -1, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,5 +41,10 @@ func (self List) String() string {
|
||||||
not = "!"
|
not = "!"
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("<list:%s[%s]>", not, self.List)
|
// var list []string
|
||||||
|
// for _, r := range self.List {
|
||||||
|
// list = append(list, string(r))
|
||||||
|
// }
|
||||||
|
|
||||||
|
return fmt.Sprintf("<list:%s[%s]>", not, string(self.List))
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ func BenchmarkIndexList(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func BenchmarkIndexListParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ func BenchmarkIndexMax(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func BenchmarkIndexMaxParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ func BenchmarkIndexMin(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func BenchmarkIndexMinParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ func BenchmarkIndexNothing(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ func BenchmarkIndexNothingParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ func BenchmarkIndexPrefixSuffix(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ func BenchmarkIndexPrefixSuffixParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ func BenchmarkIndexPrefix(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func BenchmarkIndexPrefixParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ func (self Range) Index(s string, segments []int) (int, []int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, nil
|
return -1, segments
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Range) String() string {
|
func (self Range) String() string {
|
||||||
|
@ -43,5 +43,5 @@ func (self Range) String() string {
|
||||||
if self.Not {
|
if self.Not {
|
||||||
not = "!"
|
not = "!"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("<range:%s[%s,%s]>", not, string(self.Lo), string(self.Hi))
|
return fmt.Sprintf("<range:%s[%s-%s]>", not, string(self.Lo), string(self.Hi))
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ func BenchmarkIndexRange(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ func BenchmarkIndexRangeParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ func (self Row) Len() (l int) {
|
||||||
|
|
||||||
func (self Row) Index(s string, segments []int) (int, []int) {
|
func (self Row) Index(s string, segments []int) (int, []int) {
|
||||||
if !self.lenOk(s) {
|
if !self.lenOk(s) {
|
||||||
return -1, nil
|
return -1, segments
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range s {
|
for i := range s {
|
||||||
|
@ -70,7 +70,7 @@ func (self Row) Index(s string, segments []int) (int, []int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, nil
|
return -1, segments
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Row) String() string {
|
func (self Row) String() string {
|
||||||
|
|
|
@ -62,7 +62,7 @@ func BenchmarkRowIndex(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ func BenchmarkIndexRowParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
package match
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkPerfPoolSequenced(b *testing.B) {
|
||||||
|
pool := NewPoolSequenced(512, func() []int {
|
||||||
|
return make([]int, 0, 16)
|
||||||
|
})
|
||||||
|
|
||||||
|
b.SetParallelism(32)
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
s := pool.Get()
|
||||||
|
pool.Put(s)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPerfPoolSynced(b *testing.B) {
|
||||||
|
pool := NewPoolSynced(32)
|
||||||
|
|
||||||
|
b.SetParallelism(32)
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
s := pool.Get()
|
||||||
|
pool.Put(s)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPerfPoolNative(b *testing.B) {
|
||||||
|
pool := NewPoolNative(func() []int {
|
||||||
|
return make([]int, 0, 16)
|
||||||
|
})
|
||||||
|
|
||||||
|
b.SetParallelism(32)
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
s := pool.Get()
|
||||||
|
pool.Put(s)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPerfPoolStatic(b *testing.B) {
|
||||||
|
pool := NewPoolStatic(32, func() []int {
|
||||||
|
return make([]int, 0, 16)
|
||||||
|
})
|
||||||
|
|
||||||
|
b.SetParallelism(32)
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
i, v := pool.Get()
|
||||||
|
pool.Put(i, v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPerfMake(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = make([]int, 0, 32)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
package match
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
var segmentsPools [1024]*PoolNative
|
||||||
|
|
||||||
|
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 (
|
||||||
|
minSegment = 4
|
||||||
|
minSegmentMinusOne = 3
|
||||||
|
maxSegment = 1024
|
||||||
|
maxSegmentMinusOne = 1023
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := maxSegment; i >= minSegment; i >>= 1 {
|
||||||
|
func(i int) {
|
||||||
|
segmentsPools[i-1] = NewPoolNative(func() []int {
|
||||||
|
return make([]int, 0, i)
|
||||||
|
})
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIdx(c int) int {
|
||||||
|
p := toPowerOfTwo(c)
|
||||||
|
switch {
|
||||||
|
case p >= maxSegment:
|
||||||
|
return maxSegmentMinusOne
|
||||||
|
case p <= minSegment:
|
||||||
|
return minSegmentMinusOne
|
||||||
|
default:
|
||||||
|
return p - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func acquireSegments(c int) []int {
|
||||||
|
return segmentsPools[getIdx(c)].Get()
|
||||||
|
}
|
||||||
|
|
||||||
|
func releaseSegments(s []int) {
|
||||||
|
segmentsPools[getIdx(cap(s))].Put(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
type newSegmentsFunc func() []int
|
||||||
|
|
||||||
|
// Pool holds Clients.
|
||||||
|
type PoolSequenced struct {
|
||||||
|
new newSegmentsFunc
|
||||||
|
pool chan []int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPool creates a new pool of Clients.
|
||||||
|
func NewPoolSequenced(size int, f newSegmentsFunc) *PoolSequenced {
|
||||||
|
return &PoolSequenced{
|
||||||
|
new: f,
|
||||||
|
pool: make(chan []int, size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Borrow a Client from the pool.
|
||||||
|
func (p *PoolSequenced) Get() []int {
|
||||||
|
var s []int
|
||||||
|
select {
|
||||||
|
case s = <-p.pool:
|
||||||
|
default:
|
||||||
|
s = p.new()
|
||||||
|
}
|
||||||
|
|
||||||
|
return s[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return returns a Client to the pool.
|
||||||
|
func (p *PoolSequenced) Put(s []int) {
|
||||||
|
select {
|
||||||
|
case p.pool <- s:
|
||||||
|
default:
|
||||||
|
// let it go, let it go...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PoolSynced struct {
|
||||||
|
size int
|
||||||
|
mu sync.Mutex
|
||||||
|
list [][]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPoolSynced(size int) *PoolSynced {
|
||||||
|
return &PoolSynced{
|
||||||
|
size: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PoolSynced) Get() []int {
|
||||||
|
var s []int
|
||||||
|
|
||||||
|
p.mu.Lock()
|
||||||
|
ll := len(p.list)
|
||||||
|
if ll > 0 {
|
||||||
|
s, p.list = p.list[ll-1], p.list[:ll-1]
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
|
||||||
|
if s == nil {
|
||||||
|
return make([]int, 0, p.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PoolSynced) Put(s []int) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
p.list = append(p.list, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PoolNative struct {
|
||||||
|
pool *sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPoolNative(f newSegmentsFunc) *PoolNative {
|
||||||
|
return &PoolNative{
|
||||||
|
pool: &sync.Pool{New: func() interface{} {
|
||||||
|
return f()
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PoolNative) Get() []int {
|
||||||
|
return p.pool.Get().([]int)[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PoolNative) Put(s []int) {
|
||||||
|
p.pool.Put(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
type segments struct {
|
||||||
|
data []int
|
||||||
|
locked int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type PoolStatic struct {
|
||||||
|
f newSegmentsFunc
|
||||||
|
pool []*segments
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPoolStatic(size int, f newSegmentsFunc) *PoolStatic {
|
||||||
|
p := &PoolStatic{
|
||||||
|
f: f,
|
||||||
|
pool: make([]*segments, 0, size),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
p.pool = append(p.pool, &segments{
|
||||||
|
data: f(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PoolStatic) Get() (int, []int) {
|
||||||
|
for i, s := range p.pool {
|
||||||
|
if atomic.CompareAndSwapInt32(&s.locked, 0, 1) {
|
||||||
|
return i, s.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1, p.f()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PoolStatic) Put(i int, s []int) {
|
||||||
|
if i < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.pool[i].data = s
|
||||||
|
atomic.CompareAndSwapInt32(&(p.pool[i].locked), 1, 0)
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ func BenchmarkIndexSingle(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func BenchmarkIndexSingleParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ func BenchmarkIndexSuffix(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func BenchmarkIndexSuffixParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ func BenchmarkIndexSuper(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ func BenchmarkIndexSuperParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ func (self Text) Len() int {
|
||||||
func (self Text) Index(s string, segments []int) (int, []int) {
|
func (self Text) Index(s string, segments []int) (int, []int) {
|
||||||
index := strings.Index(s, self.Str)
|
index := strings.Index(s, self.Str)
|
||||||
if index == -1 {
|
if index == -1 {
|
||||||
return -1, nil
|
return -1, segments
|
||||||
}
|
}
|
||||||
|
|
||||||
return index, append(segments, self.BytesLength)
|
return index, append(segments, self.BytesLength)
|
||||||
|
|
|
@ -41,7 +41,7 @@ func BenchmarkIndexText(b *testing.B) {
|
||||||
in := make([]int, 0, len(bench_pattern))
|
in := make([]int, 0, len(bench_pattern))
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func BenchmarkIndexTextParallel(b *testing.B) {
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
m.Index(bench_pattern, in[:0])
|
_, in = m.Index(bench_pattern, in[:0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue