Sethmr
Sethmr

Reputation: 3074

Assign count variable over calling .count on Array in Swift

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?

Upvotes: 6

Views: 1411

Answers (4)

Sethmr
Sethmr

Reputation: 3074

Array.count is a precomputed value. Since it doesn't compute it on the fly, it is far less work to use it than to use memory to store it a second time. Even so, neither method should matter unless being done in the millions+.

Upvotes: 0

dfrib
dfrib

Reputation: 73186

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.

Upvotes: 5

Lu_
Lu_

Reputation: 2685

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
    }
}

Upvotes: 2

Jack Lawrence
Jack Lawrence

Reputation: 10772

It doesn't matter; I'd suggest just doing whatever makes your code simpler and easier to understand. In release builds, the optimizer should inline and notice that the value will be the same across calls. Regardless, Array.count is basically equivalent in performance/codegen to accessing a local variable.

Upvotes: 1

Related Questions