Skip to content

Commit 90368fb

Browse files
authored
unmarshal: optimize slice capacity growth in unmarshalArray function (#87)
When unmarshaling an array from a plist file into a slice, two issues occur related to slice capacity growth: - Unnecessary growth: The slice grows even when the current capacity is enough to hold all elements. Specifically, the slice grows `if cnt >= val.Cap()`, even when the current capacity is sufficient. - Doubling capacity: The slice's capacity is always doubled, which is inefficient. It should follow a more dynamic growth pattern, similar to Go's built-in slice growth algorithm. Fixes #86
1 parent 8423e05 commit 90368fb

File tree

1 file changed

+14
-5
lines changed

1 file changed

+14
-5
lines changed

unmarshal.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,10 @@ func (p *Decoder) unmarshalArray(a *cfArray, val reflect.Value) {
218218
// Slice of element values.
219219
// Grow slice.
220220
cnt := len(a.values) + val.Len()
221-
if cnt >= val.Cap() {
222-
ncap := 2 * cnt
223-
if ncap < 4 {
224-
ncap = 4
221+
if cnt > val.Cap() {
222+
ncap := val.Cap()
223+
for ncap < cnt {
224+
ncap = growSliceCap(ncap)
225225
}
226226
new := reflect.MakeSlice(val.Type(), val.Len(), ncap)
227227
reflect.Copy(new, val)
@@ -242,7 +242,16 @@ func (p *Decoder) unmarshalArray(a *cfArray, val reflect.Value) {
242242
p.unmarshal(sval, val.Index(n))
243243
n++
244244
}
245-
return
245+
}
246+
247+
func growSliceCap(cap int) int {
248+
if cap == 0 {
249+
return 4
250+
} else if cap < 1024 {
251+
return cap * 2 // Double for small slices
252+
} else {
253+
return cap + cap/4 // Increase by 25% for large slices
254+
}
246255
}
247256

248257
func (p *Decoder) unmarshalDictionary(dict *cfDictionary, val reflect.Value) {

0 commit comments

Comments
 (0)