From c30e486b648c1540a660802a5015aeca208274fa Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Tue, 2 Apr 2024 08:43:08 +0900 Subject: [PATCH] Further performance improvements by removing unnecessary copies --- CHANGELOG.md | 5 ++++- src/ansi.go | 2 +- src/core.go | 10 +++++++--- src/tokenizer.go | 4 ++-- src/util/chars.go | 2 +- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5f66a6..a91d7b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,10 @@ CHANGELOG 0.49.0 ------ -- Ingestion performance improved by around 40% +- Performance improvements + - Ingestion performance improved by 40% + - `--ansi` performance improved by 50% + - `--with-nth` performance improved by 30% - Added two environment variables exported to the child processes - `FZF_PREVIEW_LABEL` - `FZF_BORDER_LABEL` diff --git a/src/ansi.go b/src/ansi.go index e917a4f..53fae95 100644 --- a/src/ansi.go +++ b/src/ansi.go @@ -312,7 +312,7 @@ func parseAnsiCode(s string, delimiter byte) (int, byte, string) { // Inlined version of strconv.Atoi() that only handles positive // integers and does not allocate on error. code := 0 - for _, ch := range []byte(s) { + for _, ch := range sbytes(s) { ch -= '0' if ch > 9 { return -1, delimiter, remaining diff --git a/src/core.go b/src/core.go index 1006109..ae5e58b 100644 --- a/src/core.go +++ b/src/core.go @@ -23,6 +23,10 @@ func ustring(data []byte) string { return unsafe.String(unsafe.SliceData(data), len(data)) } +func sbytes(data string) []byte { + return unsafe.Slice(unsafe.StringData(data), len(data)) +} + // Run starts fzf func Run(opts *Options, version string, revision string) { sort := opts.Sort > 0 @@ -52,14 +56,14 @@ func Run(opts *Options, version string, revision string) { prevLineAnsiState = lineAnsiState trimmed, offsets, newState := extractColor(ustring(data), lineAnsiState, nil) lineAnsiState = newState - return util.ToChars([]byte(trimmed)), offsets + return util.ToChars(sbytes(trimmed)), offsets } } else { // When color is disabled but ansi option is given, // we simply strip out ANSI codes from the input ansiProcessor = func(data []byte) (util.Chars, *[]ansiOffset) { trimmed, _, _ := extractColor(ustring(data), nil, nil) - return util.ToChars([]byte(trimmed)), nil + return util.ToChars(sbytes(trimmed)), nil } } } @@ -106,7 +110,7 @@ func Run(opts *Options, version string, revision string) { eventBox.Set(EvtHeader, header) return false } - item.text, item.colors = ansiProcessor([]byte(transformed)) + item.text, item.colors = ansiProcessor(sbytes(transformed)) item.text.TrimTrailingWhitespaces() item.text.Index = itemIndex item.origText = &data diff --git a/src/tokenizer.go b/src/tokenizer.go index 9f9e2c1..defe8cc 100644 --- a/src/tokenizer.go +++ b/src/tokenizer.go @@ -91,7 +91,7 @@ func withPrefixLengths(tokens []string, begin int) []Token { prefixLength := begin for idx := range tokens { - chars := util.ToChars([]byte(tokens[idx])) + chars := util.ToChars(sbytes(tokens[idx])) ret[idx] = Token{&chars, int32(prefixLength)} prefixLength += chars.Length() } @@ -187,7 +187,7 @@ func Transform(tokens []Token, withNth []Range) []Token { if r.begin == r.end { idx := r.begin if idx == rangeEllipsis { - chars := util.ToChars([]byte(joinTokens(tokens))) + chars := util.ToChars(sbytes(joinTokens(tokens))) parts = append(parts, &chars) } else { if idx < 0 { diff --git a/src/util/chars.go b/src/util/chars.go index 41de924..f946da8 100644 --- a/src/util/chars.go +++ b/src/util/chars.go @@ -163,7 +163,7 @@ func (chars *Chars) ToString() string { if runes := chars.optionalRunes(); runes != nil { return string(runes) } - return string(chars.slice) + return unsafe.String(unsafe.SliceData(chars.slice), len(chars.slice)) } func (chars *Chars) ToRunes() []rune {