I occasionally come to a place where I will not be changing the contents of an array, but I need to know its count several times over a function. Is it more efficient to assign the .count of the array to a variable and use it multiple times, or does the compiler make the efficiency equivalent?
Let's investigate! Is myArray.count
equivalent to accessing a stored property or is it a computed property performing some "unnecessary" calculations if called repeatedly for a non-mutated array? (Disregarding compiler cleverness)
/// The number of elements in the array. public var count: Int { return _getCount() } // ... what is function _getCount()? internal func _getCount() -> Int { return _buffer.count } // ... what is property _buffer? internal var _buffer: _Buffer // ... what is type _Buffer? (Swift) internal typealias _Buffer = _ContiguousArrayBuffer<Element> // ... what is type _ContiguousArrayBuffer? // --> switch source file
import SwiftShims /// Class used whose sole instance is used as storage for empty /// arrays. The instance is defined in the runtime and statically /// initialized. See stdlib/runtime/GlobalObjects.cpp for details. internal struct _ContiguousArrayBuffer<Element> : _ArrayBufferProtocol { // ... conformance to _ArrayBufferProtocol /// The number of elements the buffer stores. internal var count: Int { get { return __bufferPointer.header.count } // ... } // ... } // ... what is property __bufferPointer? var __bufferPointer: ManagedBufferPointer<_ArrayBody, Element> // what is type _ArrayBody? // we notice for now that it is used in the following class: internal final class _EmptyArrayStorage : _ContiguousArrayStorageBase { // ... var countAndCapacity: _ArrayBody // telling name for a tuple? :) } // --> proceed to core/ArrayBody.swift
import SwiftShims // ... internal struct _ArrayBody { var _storage: _SwiftArrayBodyStorage // ... /// The number of elements stored in this Array. var count: Int { get { return _assumeNonNegative(_storage.count) } set(newCount) { _storage.count = newCount } } } // we are near our price! we need to look closer at _SwiftArrayBodyStorage, // the type of _storage, so lets look at SwiftShims, GlobalObjects.cpp // (as mentioned in source comments above), specifically // --> switch source file
struct _SwiftArrayBodyStorage { __swift_intptr_t count; __swift_uintptr_t _capacityAndFlags; }; // Yay, we found a stored property!
So in the end count
is a stored property and is not computed per call, so it should be no reason to explicitly store the arr.count
property by yourself.
struct _SwiftArrayBodyStorage {
__swift_intptr_t count;
__swift_uintptr_t _capacityAndFlags;
};
this is the struct that Swift implements. According to this count is there all the time knowing how many elements are in buffer. You probably can use that
info form: https://ankit.im/swift/2016/01/08/exploring-swift-array-implementation/
edit for more info
public var count: Int {
get {
return __bufferPointer.value.count
}
nonmutating set {
_sanityCheck(newValue >= 0)
_sanityCheck(
newValue <= capacity,
"Can't grow an array buffer past its capacity")
__bufferPointer._valuePointer.memory.count = newValue
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With