I've been snooping around the standard library implementations of Array
and ContiguousArray<Element>
. So far I gather that:
-
struct Array<Element>
wraps avar _buffer: _ContiguousArrayBuffer<Element>
(assuming no ObjC bridging) -
struct _ContiguousArrayBuffer<Element>
wraps avar _storage: __ContiguousArrayStorageBase
. -
From the way it's allocated, it looks to me like
__ContiguousArrayStorageBase
is a heap allocated object that starts off with a header and has tail allocatedElement
s. - The header is allocated by a call to
_initStorageHeader(count:capacity:)
, which assigns a new_ArrayBody
toself._storage.countAndCapacity
. -
struct _ArrayBody
looks like a wrapper for_SwiftArrayBodyStorage
-
_SwiftArrayBodyStorage
is a C++ struct that stores a count, capacity and a "elementTypeIsBridgedVerbatim"bool
.
Everything so far matches my expectations from the Swift Array design document:
This leaves me with a few questions:
- Where is
__ContiguousArrayStorageBase
defined? - Why does
_ArrayBody
wrap_SwiftArrayBodyStorage
? Why not use_SwiftArrayBodyStorage
directly? - Why doesn't any of this use
ManagedBuffer
? The bottom of the diagram above mentioned "Handled byManagedBufferPointer<_ArrayBody, T>
, but that doesn't seem to be the case.ManagedBuffer
seems to be the Swift primitive for "A heap object with some fixed layout (a header), followed by tail allocated elements". I would have expected it to be used profusely by all of these data structures, yet it doesn't seem to be. What gives? - Why do we use up a word per buffer just to store the capacity, when it could be implemented as a computed property that derives the value from
_swift_stdlib_malloc_size
(just like how the initializer already does it)? Is_swift_stdlib_malloc_size
slow enough that this "caching" is required?