mini micro optimizations
This commit is contained in:
parent
ff26b83b95
commit
1b21b8fde2
12
.gitignore
vendored
12
.gitignore
vendored
@ -1,14 +1,2 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
11
Makefile
11
Makefile
@ -14,4 +14,15 @@ check: build
|
||||
fmt: $(SOURCES)
|
||||
@gofmt -w -s $(SOURCES)
|
||||
|
||||
cpu.out: $(SOURCES)
|
||||
go test -v -run TestMMLFile -cpuprofile cpu.out
|
||||
|
||||
cpu: cpu.out
|
||||
go tool pprof -top cpu.out
|
||||
|
||||
precommit: fmt build check
|
||||
|
||||
clean:
|
||||
@rm -f *.test
|
||||
@rm -f cpu.out
|
||||
@go clean -i ./...
|
||||
|
19
char.go
19
char.go
@ -68,6 +68,22 @@ func (p *charParser) match(t rune) bool {
|
||||
return p.not
|
||||
}
|
||||
|
||||
func (p *charParser) matchBuild(t rune) bool {
|
||||
for _, ci := range p.chars {
|
||||
if ci == t {
|
||||
return !p.not
|
||||
}
|
||||
}
|
||||
|
||||
for _, ri := range p.ranges {
|
||||
if t >= ri[0] && t <= ri[1] {
|
||||
return !p.not
|
||||
}
|
||||
}
|
||||
|
||||
return p.not
|
||||
}
|
||||
|
||||
func (p *charParser) parse(t Trace, c *context) {
|
||||
// t = t.Extend(p.name)
|
||||
// t.Out1("parsing", c.offset)
|
||||
@ -86,12 +102,13 @@ func (p *charParser) parse(t Trace, c *context) {
|
||||
}
|
||||
|
||||
func (p *charParser) build(c *context) ([]*Node, bool) {
|
||||
// TODO: how to remove this check
|
||||
t, ok := c.token()
|
||||
if !ok {
|
||||
panic("damaged parser context")
|
||||
}
|
||||
|
||||
if !p.match(t) {
|
||||
if !p.matchBuild(t) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
|
37
choice.go
37
choice.go
@ -22,7 +22,7 @@ type choiceBuilder struct {
|
||||
id int
|
||||
commit CommitType
|
||||
elements []builder
|
||||
includedBy []int
|
||||
includedBy *idSet
|
||||
}
|
||||
|
||||
func newChoice(name string, ct CommitType, elements []string) *choiceDefinition {
|
||||
@ -41,9 +41,10 @@ func (d *choiceDefinition) commitType() CommitType { return d.commit }
|
||||
func (d *choiceDefinition) init(r *registry) error {
|
||||
if d.cbuilder == nil {
|
||||
d.cbuilder = &choiceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
includedBy: &idSet{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,13 +71,14 @@ func (d *choiceDefinition) setIncludedBy(r *registry, includedBy int, parsers *i
|
||||
|
||||
if d.cbuilder == nil {
|
||||
d.cbuilder = &choiceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
includedBy: &idSet{},
|
||||
}
|
||||
}
|
||||
|
||||
d.cbuilder.includedBy = appendIfMissing(d.cbuilder.includedBy, includedBy)
|
||||
d.cbuilder.includedBy.set(includedBy)
|
||||
|
||||
parsers.set(d.id)
|
||||
return setItemsIncludedBy(r, d.elements, includedBy, parsers)
|
||||
@ -131,9 +133,10 @@ func (d *choiceDefinition) parser(r *registry, parsers *idSet) (parser, error) {
|
||||
func (d *choiceDefinition) builder() builder {
|
||||
if d.cbuilder == nil {
|
||||
d.cbuilder = &choiceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
includedBy: &idSet{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,9 +175,10 @@ func (p *choiceParser) parse(t Trace, c *context) {
|
||||
var match bool
|
||||
var nextTo int
|
||||
var elementIndex int
|
||||
var foundMatch bool
|
||||
|
||||
for {
|
||||
var foundMatch bool
|
||||
foundMatch = false
|
||||
elementIndex = 0
|
||||
|
||||
for elementIndex < len(p.elements) {
|
||||
@ -222,19 +226,14 @@ func (b *choiceBuilder) nodeName() string { return b.name }
|
||||
func (b *choiceBuilder) nodeID() int { return b.id }
|
||||
|
||||
func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
|
||||
to, ok := c.store.takeMatch(c.offset, b.id)
|
||||
to, ok := c.store.takeMatch(c.offset, b.id, b.includedBy)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
for _, ib := range b.includedBy {
|
||||
c.store.takeMatchLength(c.offset, ib, to)
|
||||
}
|
||||
|
||||
var element builder
|
||||
for _, e := range b.elements {
|
||||
elementTo, match, _ := c.store.getMatch(c.offset, e.nodeID())
|
||||
if match && elementTo == to {
|
||||
if c.store.hasMatchTo(c.offset, e.nodeID(), to) {
|
||||
element = e
|
||||
break
|
||||
}
|
||||
|
10
context.go
10
context.go
@ -90,13 +90,21 @@ func (c *context) exclude(offset int, id int) {
|
||||
}
|
||||
}
|
||||
|
||||
for i := range c.isExcluded[id] {
|
||||
if c.isExcluded[id][i] == -1 {
|
||||
c.isExcluded[id][i] = offset
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.isExcluded[id] = append(c.isExcluded[id], offset)
|
||||
}
|
||||
|
||||
func (c *context) include(offset int, id int) {
|
||||
for i := range c.isExcluded[id] {
|
||||
if c.isExcluded[id][i] == offset {
|
||||
c.isExcluded[id] = append(c.isExcluded[id][:i], c.isExcluded[id][i+1:]...)
|
||||
// c.isExcluded[id] = append(c.isExcluded[id][:i], c.isExcluded[id][i+1:]...)
|
||||
c.isExcluded[id][i] = -1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
58
sequence.go
58
sequence.go
@ -25,7 +25,8 @@ type sequenceBuilder struct {
|
||||
commit CommitType
|
||||
items []builder
|
||||
ranges [][]int
|
||||
includedBy []int
|
||||
includedBy *idSet
|
||||
allChars bool
|
||||
}
|
||||
|
||||
func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition {
|
||||
@ -48,12 +49,14 @@ func (d *sequenceDefinition) includeItems() bool {
|
||||
func (d *sequenceDefinition) init(r *registry) error {
|
||||
if d.sbuilder == nil {
|
||||
d.sbuilder = &sequenceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
includedBy: &idSet{},
|
||||
}
|
||||
}
|
||||
|
||||
allChars := true
|
||||
for _, item := range d.items {
|
||||
if item.Min == 0 && item.Max == 0 {
|
||||
item.Min, item.Max = 1, 1
|
||||
@ -69,9 +72,16 @@ func (d *sequenceDefinition) init(r *registry) error {
|
||||
}
|
||||
|
||||
d.sbuilder.items = append(d.sbuilder.items, def.builder())
|
||||
|
||||
if allChars {
|
||||
if _, isChar := def.(*charParser); !isChar {
|
||||
allChars = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d.sbuilder.ranges = d.ranges
|
||||
d.sbuilder.allChars = allChars
|
||||
|
||||
if !d.includeItems() {
|
||||
return nil
|
||||
@ -91,13 +101,14 @@ func (d *sequenceDefinition) setIncludedBy(r *registry, includedBy int, parsers
|
||||
|
||||
if d.sbuilder == nil {
|
||||
d.sbuilder = &sequenceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
includedBy: &idSet{},
|
||||
}
|
||||
}
|
||||
|
||||
d.sbuilder.includedBy = appendIfMissing(d.sbuilder.includedBy, includedBy)
|
||||
d.sbuilder.includedBy.set(includedBy)
|
||||
|
||||
if !d.includeItems() {
|
||||
return nil
|
||||
@ -158,9 +169,10 @@ func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error)
|
||||
func (d *sequenceDefinition) builder() builder {
|
||||
if d.sbuilder == nil {
|
||||
d.sbuilder = &sequenceBuilder{
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
name: d.name,
|
||||
id: d.id,
|
||||
commit: d.commit,
|
||||
includedBy: &idSet{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,16 +198,13 @@ func (p *sequenceParser) parse(t Trace, c *context) {
|
||||
return
|
||||
}
|
||||
|
||||
// if c.store.hasNoMatch(c.offset, p.id) {
|
||||
// c.fail(c.offset)
|
||||
// }
|
||||
|
||||
c.exclude(c.offset, p.id)
|
||||
|
||||
itemIndex := 0
|
||||
var currentCount int
|
||||
from := c.offset
|
||||
to := c.offset
|
||||
var parsed bool
|
||||
|
||||
for itemIndex < len(p.items) {
|
||||
// TODO: is it ok to parse before max range check? what if max=0
|
||||
@ -214,7 +223,7 @@ func (p *sequenceParser) parse(t Trace, c *context) {
|
||||
continue
|
||||
}
|
||||
|
||||
parsed := c.offset > to
|
||||
parsed = c.offset > to
|
||||
if parsed {
|
||||
currentCount++
|
||||
}
|
||||
@ -244,13 +253,24 @@ func (b *sequenceBuilder) nodeName() string { return b.name }
|
||||
func (b *sequenceBuilder) nodeID() int { return b.id }
|
||||
|
||||
func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
|
||||
to, ok := c.store.takeMatch(c.offset, b.id)
|
||||
to, ok := c.store.takeMatch(c.offset, b.id, b.includedBy)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
for _, ib := range b.includedBy {
|
||||
c.store.takeMatchLength(c.offset, ib, to)
|
||||
if b.allChars {
|
||||
from := c.offset
|
||||
c.offset = to
|
||||
if b.commit&Alias != 0 {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
return []*Node{{
|
||||
Name: b.name,
|
||||
From: from,
|
||||
To: to,
|
||||
tokens: c.tokens,
|
||||
}}, true
|
||||
}
|
||||
|
||||
from := c.offset
|
||||
|
86
store.go
86
store.go
@ -10,16 +10,8 @@ type store struct {
|
||||
match [][]int
|
||||
}
|
||||
|
||||
func (s *store) hasNoMatch(offset, id int) bool {
|
||||
if len(s.noMatch) <= offset || s.noMatch[offset] == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return s.noMatch[offset].has(id)
|
||||
}
|
||||
|
||||
func (s *store) getMatch(offset, id int) (int, bool, bool) {
|
||||
if s.hasNoMatch(offset, id) {
|
||||
if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) {
|
||||
return 0, false, true
|
||||
}
|
||||
|
||||
@ -46,11 +38,29 @@ func (s *store) getMatch(offset, id int) (int, bool, bool) {
|
||||
return to, found, found
|
||||
}
|
||||
|
||||
func (s *store) takeMatch(offset, id int) (int, bool) {
|
||||
if s.hasNoMatch(offset, id) {
|
||||
return 0, false
|
||||
func (s *store) hasMatchTo(offset, id, to int) bool {
|
||||
if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(s.match) <= offset {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(s.match[offset]); i += 2 {
|
||||
if s.match[offset][i] != id {
|
||||
continue
|
||||
}
|
||||
|
||||
if s.match[offset][i+1] == to {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *store) takeMatch(offset, id int, includedBy *idSet) (int, bool) {
|
||||
if len(s.match) <= offset {
|
||||
return 0, false
|
||||
}
|
||||
@ -75,43 +85,27 @@ func (s *store) takeMatch(offset, id int) (int, bool) {
|
||||
|
||||
if found {
|
||||
s.match[offset][index] = -1
|
||||
for i := 0; i < len(s.match[offset]); i += 2 {
|
||||
if includedBy.has(s.match[offset][i]) && s.match[offset][i+1] == to {
|
||||
s.match[offset][i] = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return to, found
|
||||
}
|
||||
|
||||
func (s *store) takeMatchLength(offset, id, to int) (int, bool) {
|
||||
if s.hasNoMatch(offset, id) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (s *store) takeMatchLength(offset, id, to int) {
|
||||
if len(s.match) <= offset {
|
||||
return 0, false
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
found bool
|
||||
// index int
|
||||
)
|
||||
|
||||
for i := 0; i < len(s.match[offset]); i += 2 {
|
||||
if s.match[offset][i] != id {
|
||||
continue
|
||||
}
|
||||
|
||||
found = true
|
||||
if s.match[offset][i+1] == to {
|
||||
if s.match[offset][i] == id && s.match[offset][i+1] == to {
|
||||
s.match[offset][i] = -1
|
||||
return to, true
|
||||
//eindex = i
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
// s.match[offset][index] = -1
|
||||
}
|
||||
|
||||
return to, found
|
||||
}
|
||||
|
||||
func (s *store) ensureOffset(offset int) {
|
||||
@ -131,15 +125,29 @@ func (s *store) ensureOffset(offset int) {
|
||||
}
|
||||
|
||||
func (s *store) setMatch(offset, id, to int) {
|
||||
if toe, match, ok := s.getMatch(offset, id); ok && match && toe == to {
|
||||
s.ensureOffset(offset)
|
||||
for i := 0; i < len(s.match[offset]); i += 2 {
|
||||
if s.match[offset][i] != id || s.match[offset][i+1] != to {
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s.ensureOffset(offset)
|
||||
s.match[offset] = append(s.match[offset], id, to)
|
||||
}
|
||||
|
||||
func (s *store) setNoMatch(offset, id int) {
|
||||
if len(s.match) > offset {
|
||||
for i := 0; i < len(s.match[offset]); i += 2 {
|
||||
if s.match[offset][i] != id {
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.noMatch) <= offset {
|
||||
if cap(s.noMatch) > offset {
|
||||
s.noMatch = s.noMatch[:offset+1]
|
||||
|
Loading…
Reference in New Issue
Block a user