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
|
*.test
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
|
||||||
*.out
|
*.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)
|
fmt: $(SOURCES)
|
||||||
@gofmt -w -s $(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
|
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
|
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) {
|
func (p *charParser) parse(t Trace, c *context) {
|
||||||
// t = t.Extend(p.name)
|
// t = t.Extend(p.name)
|
||||||
// t.Out1("parsing", c.offset)
|
// 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) {
|
func (p *charParser) build(c *context) ([]*Node, bool) {
|
||||||
|
// TODO: how to remove this check
|
||||||
t, ok := c.token()
|
t, ok := c.token()
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("damaged parser context")
|
panic("damaged parser context")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !p.match(t) {
|
if !p.matchBuild(t) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
choice.go
37
choice.go
@ -22,7 +22,7 @@ type choiceBuilder struct {
|
|||||||
id int
|
id int
|
||||||
commit CommitType
|
commit CommitType
|
||||||
elements []builder
|
elements []builder
|
||||||
includedBy []int
|
includedBy *idSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func newChoice(name string, ct CommitType, elements []string) *choiceDefinition {
|
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 {
|
func (d *choiceDefinition) init(r *registry) error {
|
||||||
if d.cbuilder == nil {
|
if d.cbuilder == nil {
|
||||||
d.cbuilder = &choiceBuilder{
|
d.cbuilder = &choiceBuilder{
|
||||||
name: d.name,
|
name: d.name,
|
||||||
id: d.id,
|
id: d.id,
|
||||||
commit: d.commit,
|
commit: d.commit,
|
||||||
|
includedBy: &idSet{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,13 +71,14 @@ func (d *choiceDefinition) setIncludedBy(r *registry, includedBy int, parsers *i
|
|||||||
|
|
||||||
if d.cbuilder == nil {
|
if d.cbuilder == nil {
|
||||||
d.cbuilder = &choiceBuilder{
|
d.cbuilder = &choiceBuilder{
|
||||||
name: d.name,
|
name: d.name,
|
||||||
id: d.id,
|
id: d.id,
|
||||||
commit: d.commit,
|
commit: d.commit,
|
||||||
|
includedBy: &idSet{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.cbuilder.includedBy = appendIfMissing(d.cbuilder.includedBy, includedBy)
|
d.cbuilder.includedBy.set(includedBy)
|
||||||
|
|
||||||
parsers.set(d.id)
|
parsers.set(d.id)
|
||||||
return setItemsIncludedBy(r, d.elements, includedBy, parsers)
|
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 {
|
func (d *choiceDefinition) builder() builder {
|
||||||
if d.cbuilder == nil {
|
if d.cbuilder == nil {
|
||||||
d.cbuilder = &choiceBuilder{
|
d.cbuilder = &choiceBuilder{
|
||||||
name: d.name,
|
name: d.name,
|
||||||
id: d.id,
|
id: d.id,
|
||||||
commit: d.commit,
|
commit: d.commit,
|
||||||
|
includedBy: &idSet{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +175,10 @@ func (p *choiceParser) parse(t Trace, c *context) {
|
|||||||
var match bool
|
var match bool
|
||||||
var nextTo int
|
var nextTo int
|
||||||
var elementIndex int
|
var elementIndex int
|
||||||
|
var foundMatch bool
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var foundMatch bool
|
foundMatch = false
|
||||||
elementIndex = 0
|
elementIndex = 0
|
||||||
|
|
||||||
for elementIndex < len(p.elements) {
|
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) nodeID() int { return b.id }
|
||||||
|
|
||||||
func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
|
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 {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ib := range b.includedBy {
|
|
||||||
c.store.takeMatchLength(c.offset, ib, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
var element builder
|
var element builder
|
||||||
for _, e := range b.elements {
|
for _, e := range b.elements {
|
||||||
elementTo, match, _ := c.store.getMatch(c.offset, e.nodeID())
|
if c.store.hasMatchTo(c.offset, e.nodeID(), to) {
|
||||||
if match && elementTo == to {
|
|
||||||
element = e
|
element = e
|
||||||
break
|
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)
|
c.isExcluded[id] = append(c.isExcluded[id], offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) include(offset int, id int) {
|
func (c *context) include(offset int, id int) {
|
||||||
for i := range c.isExcluded[id] {
|
for i := range c.isExcluded[id] {
|
||||||
if c.isExcluded[id][i] == offset {
|
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
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
58
sequence.go
58
sequence.go
@ -25,7 +25,8 @@ type sequenceBuilder struct {
|
|||||||
commit CommitType
|
commit CommitType
|
||||||
items []builder
|
items []builder
|
||||||
ranges [][]int
|
ranges [][]int
|
||||||
includedBy []int
|
includedBy *idSet
|
||||||
|
allChars bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition {
|
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 {
|
func (d *sequenceDefinition) init(r *registry) error {
|
||||||
if d.sbuilder == nil {
|
if d.sbuilder == nil {
|
||||||
d.sbuilder = &sequenceBuilder{
|
d.sbuilder = &sequenceBuilder{
|
||||||
name: d.name,
|
name: d.name,
|
||||||
id: d.id,
|
id: d.id,
|
||||||
commit: d.commit,
|
commit: d.commit,
|
||||||
|
includedBy: &idSet{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allChars := true
|
||||||
for _, item := range d.items {
|
for _, item := range d.items {
|
||||||
if item.Min == 0 && item.Max == 0 {
|
if item.Min == 0 && item.Max == 0 {
|
||||||
item.Min, item.Max = 1, 1
|
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())
|
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.ranges = d.ranges
|
||||||
|
d.sbuilder.allChars = allChars
|
||||||
|
|
||||||
if !d.includeItems() {
|
if !d.includeItems() {
|
||||||
return nil
|
return nil
|
||||||
@ -91,13 +101,14 @@ func (d *sequenceDefinition) setIncludedBy(r *registry, includedBy int, parsers
|
|||||||
|
|
||||||
if d.sbuilder == nil {
|
if d.sbuilder == nil {
|
||||||
d.sbuilder = &sequenceBuilder{
|
d.sbuilder = &sequenceBuilder{
|
||||||
name: d.name,
|
name: d.name,
|
||||||
id: d.id,
|
id: d.id,
|
||||||
commit: d.commit,
|
commit: d.commit,
|
||||||
|
includedBy: &idSet{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.sbuilder.includedBy = appendIfMissing(d.sbuilder.includedBy, includedBy)
|
d.sbuilder.includedBy.set(includedBy)
|
||||||
|
|
||||||
if !d.includeItems() {
|
if !d.includeItems() {
|
||||||
return nil
|
return nil
|
||||||
@ -158,9 +169,10 @@ func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error)
|
|||||||
func (d *sequenceDefinition) builder() builder {
|
func (d *sequenceDefinition) builder() builder {
|
||||||
if d.sbuilder == nil {
|
if d.sbuilder == nil {
|
||||||
d.sbuilder = &sequenceBuilder{
|
d.sbuilder = &sequenceBuilder{
|
||||||
name: d.name,
|
name: d.name,
|
||||||
id: d.id,
|
id: d.id,
|
||||||
commit: d.commit,
|
commit: d.commit,
|
||||||
|
includedBy: &idSet{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,16 +198,13 @@ func (p *sequenceParser) parse(t Trace, c *context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// if c.store.hasNoMatch(c.offset, p.id) {
|
|
||||||
// c.fail(c.offset)
|
|
||||||
// }
|
|
||||||
|
|
||||||
c.exclude(c.offset, p.id)
|
c.exclude(c.offset, p.id)
|
||||||
|
|
||||||
itemIndex := 0
|
itemIndex := 0
|
||||||
var currentCount int
|
var currentCount int
|
||||||
from := c.offset
|
from := c.offset
|
||||||
to := c.offset
|
to := c.offset
|
||||||
|
var parsed bool
|
||||||
|
|
||||||
for itemIndex < len(p.items) {
|
for itemIndex < len(p.items) {
|
||||||
// TODO: is it ok to parse before max range check? what if max=0
|
// 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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
parsed := c.offset > to
|
parsed = c.offset > to
|
||||||
if parsed {
|
if parsed {
|
||||||
currentCount++
|
currentCount++
|
||||||
}
|
}
|
||||||
@ -244,13 +253,24 @@ func (b *sequenceBuilder) nodeName() string { return b.name }
|
|||||||
func (b *sequenceBuilder) nodeID() int { return b.id }
|
func (b *sequenceBuilder) nodeID() int { return b.id }
|
||||||
|
|
||||||
func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
|
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 {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ib := range b.includedBy {
|
if b.allChars {
|
||||||
c.store.takeMatchLength(c.offset, ib, to)
|
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
|
from := c.offset
|
||||||
|
86
store.go
86
store.go
@ -10,16 +10,8 @@ type store struct {
|
|||||||
match [][]int
|
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) {
|
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
|
return 0, false, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,11 +38,29 @@ func (s *store) getMatch(offset, id int) (int, bool, bool) {
|
|||||||
return to, found, found
|
return to, found, found
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) takeMatch(offset, id int) (int, bool) {
|
func (s *store) hasMatchTo(offset, id, to int) bool {
|
||||||
if s.hasNoMatch(offset, id) {
|
if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) {
|
||||||
return 0, false
|
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 {
|
if len(s.match) <= offset {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@ -75,43 +85,27 @@ func (s *store) takeMatch(offset, id int) (int, bool) {
|
|||||||
|
|
||||||
if found {
|
if found {
|
||||||
s.match[offset][index] = -1
|
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
|
return to, found
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) takeMatchLength(offset, id, to int) (int, bool) {
|
func (s *store) takeMatchLength(offset, id, to int) {
|
||||||
if s.hasNoMatch(offset, id) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.match) <= offset {
|
if len(s.match) <= offset {
|
||||||
return 0, false
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
found bool
|
|
||||||
// index int
|
|
||||||
)
|
|
||||||
|
|
||||||
for i := 0; i < len(s.match[offset]); i += 2 {
|
for i := 0; i < len(s.match[offset]); i += 2 {
|
||||||
if s.match[offset][i] != id {
|
if s.match[offset][i] == id && s.match[offset][i+1] == to {
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
found = true
|
|
||||||
if s.match[offset][i+1] == to {
|
|
||||||
s.match[offset][i] = -1
|
s.match[offset][i] = -1
|
||||||
return to, true
|
return
|
||||||
//eindex = i
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if found {
|
|
||||||
// s.match[offset][index] = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
return to, found
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) ensureOffset(offset int) {
|
func (s *store) ensureOffset(offset int) {
|
||||||
@ -131,15 +125,29 @@ func (s *store) ensureOffset(offset int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) setMatch(offset, id, to 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.ensureOffset(offset)
|
|
||||||
s.match[offset] = append(s.match[offset], id, to)
|
s.match[offset] = append(s.match[offset], id, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) setNoMatch(offset, id int) {
|
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 len(s.noMatch) <= offset {
|
||||||
if cap(s.noMatch) > offset {
|
if cap(s.noMatch) > offset {
|
||||||
s.noMatch = s.noMatch[:offset+1]
|
s.noMatch = s.noMatch[:offset+1]
|
||||||
|
Loading…
Reference in New Issue
Block a user