How can String be only 16 bytes, when _StringGuts is 20?

// Adapted from https://github.com/apple/swift/blob/swift-5.0-branch/stdlib/public/core/StringObject.swift#L64-L112
internal typealias _CocoaString = AnyObject

internal struct _StringObject {
	internal enum Variant {
		case immortal(UInt)
		case native(AnyObject)
		case bridged(_CocoaString)
	}

	internal var _count: Int
	internal var _variant: Variant
	internal var _discriminator: UInt8
	internal var _flags: UInt16
}

// Adapted from https://github.com/apple/swift/blob/swift-5.0-branch/stdlib/public/core/StringGuts.swift#L21-L23
struct _StringGuts {
	@usableFromInline
	internal var _object: _StringObject
}

// Adapted from https://github.com/apple/swift/blob/swift-5.0-branch/stdlib/public/core/String.swift#L352-L354
struct StringCopy {
	public // @SPI(Foundation)
	var _guts: _StringGuts
}

print(MemoryLayout<_StringObject.Variant>.size) // => 9
print(MemoryLayout<_StringObject>.size) // => 20
print(MemoryLayout<_StringGuts>.size) // => 20
print(MemoryLayout<StringCopy>.size) // => 20
print(MemoryLayout<String>.size) // => 16 🤔

What gives?

That definition of _count, _variant, _discriminator and _flags is for the 32bit (i386 and arm) definition of _StringObject where the Int is 4 bytes.

On 64bit, _StringObject is 2 64bit values:


  @usableFromInline
  internal var _countAndFlagsBits: UInt64

  @usableFromInline
  internal var _object: Builtin.BridgeObject
1 Like

D'oh! Nice catch, thanks.