Skip to content

Commit

Permalink
unmarshal: optimize slice capacity growth in unmarshalArray function (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
semihbkgr authored Jan 27, 2025
1 parent 8423e05 commit 90368fb
Showing 1 changed file with 14 additions and 5 deletions.
19 changes: 14 additions & 5 deletions unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,10 @@ func (p *Decoder) unmarshalArray(a *cfArray, val reflect.Value) {
// Slice of element values.
// Grow slice.
cnt := len(a.values) + val.Len()
if cnt >= val.Cap() {
ncap := 2 * cnt
if ncap < 4 {
ncap = 4
if cnt > val.Cap() {
ncap := val.Cap()
for ncap < cnt {
ncap = growSliceCap(ncap)
}
new := reflect.MakeSlice(val.Type(), val.Len(), ncap)
reflect.Copy(new, val)
Expand All @@ -242,7 +242,16 @@ func (p *Decoder) unmarshalArray(a *cfArray, val reflect.Value) {
p.unmarshal(sval, val.Index(n))
n++
}
return
}

func growSliceCap(cap int) int {
if cap == 0 {
return 4
} else if cap < 1024 {
return cap * 2 // Double for small slices
} else {
return cap + cap/4 // Increase by 25% for large slices
}
}

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

0 comments on commit 90368fb

Please sign in to comment.