MM-29981 - optimize markdown.Inspect (#16188)
* MM-29981 - optimize markdown.Inspect - Cache regexp.MustCompile - Reuse slice in MergeInlineText - Remove pointer to slice in closeBlocks - Pre-allocate slice in ParseLines - Some more small cleanups ``` name old time/op new time/op delta Inspect-8 10.5µs ± 3% 6.6µs ± 1% -37.59% (p=0.000 n=10+7) name old alloc/op new alloc/op delta Inspect-8 6.66kB ± 0% 3.22kB ± 0% -51.62% (p=0.000 n=10+9) name old allocs/op new allocs/op delta Inspect-8 117 ± 0% 76 ± 0% -35.04% (p=0.000 n=10+10) ``` * fix lint * remove ignore Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
95221d9ace
Коммит
eced0cdb72
@@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultUrlSchemes = []string{"http", "https", "ftp", "mailto", "tel"}
|
DefaultUrlSchemes = []string{"http", "https", "ftp", "mailto", "tel"}
|
||||||
|
wwwAutoLinkRegex = regexp.MustCompile(`^www\d{0,3}\.`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Given a string with a w at the given position, tries to parse and return a range containing a www link.
|
// Given a string with a w at the given position, tries to parse and return a range containing a www link.
|
||||||
@@ -30,7 +31,7 @@ func parseWWWAutolink(data string, position int) (Range, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that this starts with www
|
// Check that this starts with www
|
||||||
if len(data)-position < 4 || !regexp.MustCompile(`^www\d{0,3}\.`).MatchString(data[position:]) {
|
if len(data)-position < 4 || !wwwAutoLinkRegex.MatchString(data[position:]) {
|
||||||
return Range{}, false
|
return Range{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,9 +60,8 @@ func isAllowedBeforeWWWLink(c byte) bool {
|
|||||||
switch c {
|
switch c {
|
||||||
case '*', '_', '~', ')':
|
case '*', '_', '~', ')':
|
||||||
return true
|
return true
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a string with a : at the given position, tried to parse and return a range containing a URL scheme
|
// Given a string with a : at the given position, tried to parse and return a range containing a URL scheme
|
||||||
@@ -153,9 +153,8 @@ func checkDomain(data string, allowShort bool) int {
|
|||||||
// this is called from parseWWWAutolink
|
// this is called from parseWWWAutolink
|
||||||
if foundPeriod {
|
if foundPeriod {
|
||||||
return i
|
return i
|
||||||
} else {
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the provided link starts with a valid character for a domain name. Equivalent to
|
// Returns true if the provided link starts with a valid character for a domain name. Equivalent to
|
||||||
@@ -251,7 +250,6 @@ func canEndAutolink(c rune) bool {
|
|||||||
switch c {
|
switch c {
|
||||||
case '?', '!', '.', ',', ':', '*', '_', '~', '\'', '"':
|
case '?', '!', '.', ',', ':', '*', '_', '~', '\'', '"':
|
||||||
return false
|
return false
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,13 +37,14 @@ type Range struct {
|
|||||||
End int
|
End int
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeBlocks(blocks []Block, referenceDefinitions *[]*ReferenceDefinition) {
|
func closeBlocks(blocks []Block, referenceDefinitions []*ReferenceDefinition) []*ReferenceDefinition {
|
||||||
for _, block := range blocks {
|
for _, block := range blocks {
|
||||||
block.Close()
|
block.Close()
|
||||||
if p, ok := block.(*Paragraph); ok && len(p.ReferenceDefinitions) > 0 {
|
if p, ok := block.(*Paragraph); ok && len(p.ReferenceDefinitions) > 0 {
|
||||||
*referenceDefinitions = append(*referenceDefinitions, p.ReferenceDefinitions...)
|
referenceDefinitions = append(referenceDefinitions, p.ReferenceDefinitions...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return referenceDefinitions
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseBlocks(markdown string, lines []Line) (*Document, []*ReferenceDefinition) {
|
func ParseBlocks(markdown string, lines []Line) (*Document, []*ReferenceDefinition) {
|
||||||
@@ -78,7 +79,7 @@ func ParseBlocks(markdown string, lines []Line) (*Document, []*ReferenceDefiniti
|
|||||||
for i := lastMatchIndex; i >= 0; i-- {
|
for i := lastMatchIndex; i >= 0; i-- {
|
||||||
if container, ok := openBlocks[i].(ContainerBlock); ok {
|
if container, ok := openBlocks[i].(ContainerBlock); ok {
|
||||||
if addedBlocks := container.AddChild(newBlocks); addedBlocks != nil {
|
if addedBlocks := container.AddChild(newBlocks); addedBlocks != nil {
|
||||||
closeBlocks(openBlocks[i+1:], &referenceDefinitions)
|
referenceDefinitions = closeBlocks(openBlocks[i+1:], referenceDefinitions)
|
||||||
openBlocks = openBlocks[:i+1]
|
openBlocks = openBlocks[:i+1]
|
||||||
openBlocks = append(openBlocks, addedBlocks...)
|
openBlocks = append(openBlocks, addedBlocks...)
|
||||||
didAdd = true
|
didAdd = true
|
||||||
@@ -98,7 +99,7 @@ func ParseBlocks(markdown string, lines []Line) (*Document, []*ReferenceDefiniti
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
closeBlocks(openBlocks[lastMatchIndex+1:], &referenceDefinitions)
|
referenceDefinitions = closeBlocks(openBlocks[lastMatchIndex+1:], referenceDefinitions)
|
||||||
openBlocks = openBlocks[:lastMatchIndex+1]
|
openBlocks = openBlocks[:lastMatchIndex+1]
|
||||||
|
|
||||||
if openBlocks[lastMatchIndex].AddLine(indentation, r) {
|
if openBlocks[lastMatchIndex].AddLine(indentation, r) {
|
||||||
@@ -109,7 +110,7 @@ func ParseBlocks(markdown string, lines []Line) (*Document, []*ReferenceDefiniti
|
|||||||
for i := lastMatchIndex; i >= 0; i-- {
|
for i := lastMatchIndex; i >= 0; i-- {
|
||||||
if container, ok := openBlocks[i].(ContainerBlock); ok {
|
if container, ok := openBlocks[i].(ContainerBlock); ok {
|
||||||
if newBlocks := container.AddChild([]Block{paragraph}); newBlocks != nil {
|
if newBlocks := container.AddChild([]Block{paragraph}); newBlocks != nil {
|
||||||
closeBlocks(openBlocks[i+1:], &referenceDefinitions)
|
referenceDefinitions = closeBlocks(openBlocks[i+1:], referenceDefinitions)
|
||||||
openBlocks = openBlocks[:i+1]
|
openBlocks = openBlocks[:i+1]
|
||||||
openBlocks = append(openBlocks, newBlocks...)
|
openBlocks = append(openBlocks, newBlocks...)
|
||||||
break
|
break
|
||||||
@@ -119,7 +120,7 @@ func ParseBlocks(markdown string, lines []Line) (*Document, []*ReferenceDefiniti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closeBlocks(openBlocks, &referenceDefinitions)
|
referenceDefinitions = closeBlocks(openBlocks, referenceDefinitions)
|
||||||
|
|
||||||
return document, referenceDefinitions
|
return document, referenceDefinitions
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -595,7 +595,7 @@ func ParseInlines(markdown string, ranges []Range, referenceDefinitions []*Refer
|
|||||||
}
|
}
|
||||||
|
|
||||||
func MergeInlineText(inlines []Inline) []Inline {
|
func MergeInlineText(inlines []Inline) []Inline {
|
||||||
var ret []Inline
|
ret := inlines[:0]
|
||||||
for i, v := range inlines {
|
for i, v := range inlines {
|
||||||
// always add first node
|
// always add first node
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
|||||||
@@ -52,3 +52,24 @@ func TestInspect(t *testing.T) {
|
|||||||
" Text",
|
" Text",
|
||||||
}, visited)
|
}, visited)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var counterSink int
|
||||||
|
|
||||||
|
func BenchmarkInspect(b *testing.B) {
|
||||||
|
text := `Some standard piece of text.
|
||||||
|
|
||||||
|
Has a link [post](https://github.com) and also has a blockquote.
|
||||||
|
|
||||||
|
> This is a famous quote.
|
||||||
|
|
||||||
|
Some bold text **Text for markdown?** to go with it.
|
||||||
|
|
||||||
|
At the end, some more lines`
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Inspect(text, func(_ interface{}) bool {
|
||||||
|
counterSink++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,13 +3,16 @@
|
|||||||
|
|
||||||
package markdown
|
package markdown
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
type Line struct {
|
type Line struct {
|
||||||
Range
|
Range
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseLines(markdown string) (lines []Line) {
|
func ParseLines(markdown string) []Line {
|
||||||
lineStartPosition := 0
|
lineStartPosition := 0
|
||||||
isAfterCarriageReturn := false
|
isAfterCarriageReturn := false
|
||||||
|
lines := make([]Line, 0, strings.Count(markdown, "\n"))
|
||||||
for position, r := range markdown {
|
for position, r := range markdown {
|
||||||
if r == '\n' {
|
if r == '\n' {
|
||||||
lines = append(lines, Line{Range{lineStartPosition, position + 1}})
|
lines = append(lines, Line{Range{lineStartPosition, position + 1}})
|
||||||
@@ -23,5 +26,5 @@ func ParseLines(markdown string) (lines []Line) {
|
|||||||
if lineStartPosition < len(markdown) {
|
if lineStartPosition < len(markdown) {
|
||||||
lines = append(lines, Line{Range{lineStartPosition, len(markdown)}})
|
lines = append(lines, Line{Range{lineStartPosition, len(markdown)}})
|
||||||
}
|
}
|
||||||
return
|
return lines
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,8 @@ func isWhitespace(c rune) bool {
|
|||||||
switch c {
|
switch c {
|
||||||
case ' ', '\t', '\n', '\u000b', '\u000c', '\r':
|
case ' ', '\t', '\n', '\u000b', '\u000c', '\r':
|
||||||
return true
|
return true
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isWhitespaceByte(c byte) bool {
|
func isWhitespaceByte(c byte) bool {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user