mirror of
https://github.com/junegunn/fzf.git
synced 2025-08-17 21:43:50 -07:00
Reduce memory footprint of Item struct
This commit is contained in:
@@ -3,63 +3,81 @@ package util
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Chars struct {
|
||||
runes []rune
|
||||
bytes []byte
|
||||
slice []byte // or []rune
|
||||
inBytes bool
|
||||
trimLengthKnown bool
|
||||
trimLength uint16
|
||||
|
||||
// XXX Piggybacking item index here is a horrible idea. But I'm trying to
|
||||
// minimize the memory footprint by not wasting padded spaces.
|
||||
Index int32
|
||||
}
|
||||
|
||||
// ToChars converts byte array into rune array
|
||||
func ToChars(bytea []byte) Chars {
|
||||
func ToChars(bytes []byte) Chars {
|
||||
var runes []rune
|
||||
ascii := true
|
||||
numBytes := len(bytea)
|
||||
inBytes := true
|
||||
numBytes := len(bytes)
|
||||
for i := 0; i < numBytes; {
|
||||
if bytea[i] < utf8.RuneSelf {
|
||||
if !ascii {
|
||||
runes = append(runes, rune(bytea[i]))
|
||||
if bytes[i] < utf8.RuneSelf {
|
||||
if !inBytes {
|
||||
runes = append(runes, rune(bytes[i]))
|
||||
}
|
||||
i++
|
||||
} else {
|
||||
if ascii {
|
||||
ascii = false
|
||||
if inBytes {
|
||||
inBytes = false
|
||||
runes = make([]rune, i, numBytes)
|
||||
for j := 0; j < i; j++ {
|
||||
runes[j] = rune(bytea[j])
|
||||
runes[j] = rune(bytes[j])
|
||||
}
|
||||
}
|
||||
r, sz := utf8.DecodeRune(bytea[i:])
|
||||
r, sz := utf8.DecodeRune(bytes[i:])
|
||||
i += sz
|
||||
runes = append(runes, r)
|
||||
}
|
||||
}
|
||||
if ascii {
|
||||
return Chars{bytes: bytea}
|
||||
if inBytes {
|
||||
return Chars{slice: bytes, inBytes: inBytes}
|
||||
}
|
||||
return Chars{runes: runes}
|
||||
return RunesToChars(runes)
|
||||
}
|
||||
|
||||
func RunesToChars(runes []rune) Chars {
|
||||
return Chars{runes: runes}
|
||||
return Chars{slice: *(*[]byte)(unsafe.Pointer(&runes)), inBytes: false}
|
||||
}
|
||||
|
||||
func (chars *Chars) optionalRunes() []rune {
|
||||
if chars.inBytes {
|
||||
return nil
|
||||
}
|
||||
return *(*[]rune)(unsafe.Pointer(&chars.slice))
|
||||
}
|
||||
|
||||
func (chars *Chars) Get(i int) rune {
|
||||
if chars.runes != nil {
|
||||
return chars.runes[i]
|
||||
if runes := chars.optionalRunes(); runes != nil {
|
||||
return runes[i]
|
||||
}
|
||||
return rune(chars.bytes[i])
|
||||
return rune(chars.slice[i])
|
||||
}
|
||||
|
||||
func (chars *Chars) Length() int {
|
||||
if chars.runes != nil {
|
||||
return len(chars.runes)
|
||||
if runes := chars.optionalRunes(); runes != nil {
|
||||
return len(runes)
|
||||
}
|
||||
return len(chars.bytes)
|
||||
return len(chars.slice)
|
||||
}
|
||||
|
||||
// TrimLength returns the length after trimming leading and trailing whitespaces
|
||||
func (chars *Chars) TrimLength() int {
|
||||
func (chars *Chars) TrimLength() uint16 {
|
||||
if chars.trimLengthKnown {
|
||||
return chars.trimLength
|
||||
}
|
||||
chars.trimLengthKnown = true
|
||||
var i int
|
||||
len := chars.Length()
|
||||
for i = len - 1; i >= 0; i-- {
|
||||
@@ -80,7 +98,8 @@ func (chars *Chars) TrimLength() int {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i - j + 1
|
||||
chars.trimLength = AsUint16(i - j + 1)
|
||||
return chars.trimLength
|
||||
}
|
||||
|
||||
func (chars *Chars) TrailingWhitespaces() int {
|
||||
@@ -96,28 +115,40 @@ func (chars *Chars) TrailingWhitespaces() int {
|
||||
}
|
||||
|
||||
func (chars *Chars) ToString() string {
|
||||
if chars.runes != nil {
|
||||
return string(chars.runes)
|
||||
if runes := chars.optionalRunes(); runes != nil {
|
||||
return string(runes)
|
||||
}
|
||||
return string(chars.bytes)
|
||||
return string(chars.slice)
|
||||
}
|
||||
|
||||
func (chars *Chars) ToRunes() []rune {
|
||||
if chars.runes != nil {
|
||||
return chars.runes
|
||||
if runes := chars.optionalRunes(); runes != nil {
|
||||
return runes
|
||||
}
|
||||
runes := make([]rune, len(chars.bytes))
|
||||
for idx, b := range chars.bytes {
|
||||
bytes := chars.slice
|
||||
runes := make([]rune, len(bytes))
|
||||
for idx, b := range bytes {
|
||||
runes[idx] = rune(b)
|
||||
}
|
||||
return runes
|
||||
}
|
||||
|
||||
func (chars *Chars) Slice(b int, e int) Chars {
|
||||
if chars.runes != nil {
|
||||
return Chars{runes: chars.runes[b:e]}
|
||||
func (chars *Chars) CopyRunes(dest []rune) {
|
||||
if runes := chars.optionalRunes(); runes != nil {
|
||||
copy(dest, runes)
|
||||
return
|
||||
}
|
||||
return Chars{bytes: chars.bytes[b:e]}
|
||||
for idx, b := range chars.slice {
|
||||
dest[idx] = rune(b)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (chars *Chars) Slice(b int, e int) Chars {
|
||||
if runes := chars.optionalRunes(); runes != nil {
|
||||
return RunesToChars(runes[b:e])
|
||||
}
|
||||
return Chars{slice: chars.slice[b:e], inBytes: true}
|
||||
}
|
||||
|
||||
func (chars *Chars) Split(delimiter string) []Chars {
|
||||
|
Reference in New Issue
Block a user