Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift array.capacity vs array.count

Tags:

arrays

swift

I understand the array.count ( the number of elements in the array ). count is useful to iterate over the array's elements. I sort of get the gist of array.capacity

capacity An integer value that represents how many total elements the array can store without reallocation (read-only).

Experiment

I have been playing with the Playground and noticed an array's capacity is an even number ( incremented by 2 )

var arr = [1, 2, 3 , 4, 5, 6, 7]
arr.removeLast() // capacity stays the same after a removal
println(arr.capacity) // 8
println(arr.count)    // 6

var arr = [1, 2, 3 , 4, 5, 6]
arr.removeLast()
println(arr.capacity) // 6
println(arr.count)    // 5

The question

What is the use of an array capacity ? Please give a concrete example ?

like image 696
Raymond Chenon Avatar asked Jan 07 '15 23:01

Raymond Chenon


3 Answers

An array's capacity—in particular, its reserveCapacity method—lets you preallocate space in the array.

If you're adding elements to an array, and you exceed its capacity, then the array must increase its capacity. Since a Swift array stores its elements contiguously in memory, it must reallocate its internal storage and (usually) copy all of its elements from the old storage to the new storage. (Note that NSArray isn't documented to store its elements contiguously, but we can deduce that Swift Array probably does based on the existence of the withUnsafeMutableBufferPointer method.)

If you know in advance how many elements you intend to add to the array, you can use the reserveCapacity method to preset the array's capacity so that it won't need to perform any reallocations (and associated copying).

The only reasons I can think of to ask an array for its capacity are to learn how the system works, and to debug a performance problem.

Usually you don't need to worry about reserving capacity. A reallocation is rarely a performance problem. Swift uses (I believe) an efficient reallocation schedule so that the number of reallocations is logarithmic in the final count of the array. E.g. if you add a million elements one at a time, Swift should perform no more than 20-30 reallocations.

But if you know your array will be very large (like, gigabytes on a Mac or tens of megabytes on an iOS device), or if you are filling the array in a performance-sensitive code path (e.g. filling an audio buffer that will start playing within microseconds), you may want to reserve capacity and avoid reallocations.

You should probably not worry about reserving capacity unless you know reallocations are a problem, either because the profiler shows that they're a bottleneck or because you have other evidence (like audio glitches in the audio buffer example).

like image 102
rob mayoff Avatar answered Oct 29 '22 07:10

rob mayoff


What is the use of an array capacity

Basically, the array capacity has no external use. It is there for Swift's internal use. If you know that you will be allocating 100 objects to this array, you could set the capacity in advance as you create the array, and I have seen some people do that in their code; but there is no particular need to do so and no particular gain in doing so. You've looked under the hood and seen something you didn't really need to see. Now that you've seen, you can forget about it.

like image 29
matt Avatar answered Oct 29 '22 08:10

matt


The total number of elements that the array can contain without

allocating new storage.

Every array reserves a specific amount of memory to hold its contents. When you add elements to an array and that array begins to exceed its reserved capacity, the array allocates a larger region of memory and copies its elements into the new storage. The new storage is a multiple of the old storage's size. This exponential growth strategy means that appending an element happens in constant time, averaging the performance of many append operations. Append operations that trigger reallocation have a performance cost, but they occur less and less often as the array grows larger.

The following example creates an array of integers from an array literal, then appends the elements of another collection. Before appending, the array allocates new storage that is large enough store the resulting elements.

var numbers = [10, 20, 30, 40, 50]

numbers.count == 5

numbers.capacity == 5

numbers.append(contentsOf: stride(from: 60, through: 100, by: 10))

numbers.count == 10

numbers.capacity == 12
like image 1
raavan199 Avatar answered Oct 29 '22 06:10

raavan199