As the title said, I tried to prove myself that COW(copy on write) is supported for String in Swift. But I cannot find a proof. I proved the COW on Array and Dictionary after trying the following codes:
func address(of object: UnsafeRawPointer) -> String {
let addr = Int(bitPattern: object)
return String(format: "%p", addr)
}
var xArray = [20, 30, 40, 50, 60]
var yArray = xArray
// These two addresses were the same
address(of: xArray)
address(of: yArray)
yArray[0] = 200
// The address of yArray got changed
address(of: yArray)
But for String type, it was not working.
var xString = "Hello World"
var yString = xString
// These two addresses were different
address(of: xString)
address(of: yString)
And I dumped the test function from the official Swift code repo.
func _rawIdentifier(s: String) -> (UInt, UInt) {
let tripe = unsafeBitCast(s, to: (UInt, UInt, UInt).self)
let minusCount = (tripe.0, tripe.2)
return minusCount
}
But this function seems to only cast the actual value pointed to not the address. So two different String variables with the same value would have the same rawIdentifier. Still cannot prove COW to me.
var xString = "Hello World"
var yString = "Hello" + " World"
// These two rawIdentifiers were the same
_rawIdentifier(s: xString)
_rawIdentifier(s: yString)
So how does COW work on String type in Swift?
"Hello" + " World"
is folded into"Hello World"
. You could also dovar yString = "Hello"; yString += " World"
to notice a difference (the buffer will also gain an owner in that case, as it's now dynamically, rather than statically, allocated) – Violante_rawIdentifier
: UsingunsafeBitCast
bypasses retain count operations, so it is fully possible for you to be looking at dangling pointers (i.e the string buffer gets released while you're still looking at the string value) – attempting to dereference those would then be undefined behaviour. In the code you took it from, the callers used_fixLifetime
in order to guarantee this couldn't happen. You can usewithExtendedLifetime(_:_:)
to ensure this too (or use anUnsafeMutablePointer
and rebind the memory). – Violante_rawIdentifier()
does not dereference the pointer, or does it? – SpermophyteUnsafePointer
s and then try to inspect the pointees). It was more of a pre-emptive warning :) – Violante