In response to both Question 1 and Question 2: Swift really needs an API for this:
Add withUnsafeElements(to: variable) where variable is any homogenous aggregate
Now for pedantry on Question 2:
Alternative 3 is the intended way to interface with UnsafeRawPointer:
$0.load(fromByteOffset: Int(i) &* 4, as: UInt32.self)
A withUnsafeElements()
API would be nicer because you wouldn't need to do any pointer arithmetic.
The memory binding APIs are not meant for common use, only for writing low-level Swift data types.
// Alternative 1:
$0.bindMemory(to: UInt32.self)[Int(i)]
In general, it doesn't make sense to call bindMemory
on the address of a local variable, because the variable itself is bound to a type. Rebinding the same memory to a different type implicitly invalidates that variable. In this special case it's correct because UInt32 type is "related" to a homogenous tuple of UInt32 and they are layout compatible. In other words, this call to bindMemory
doesn't really have any effect, so it's a safe way to just get a new pointer type. If you we're rebinding memory to Int32 instead, and reading from the results
variable again after doing that, then it would be undefined. That's an easy mistake to make, so it's better to just avoid this API altogether unless you're writing a custom memory allocator in Swift!
// Alternative 2:
$0.baseAddress!.assumingMemoryBound(to: UInt32.self)[Int(i)]
Calling assumingMemoryBound
is only intended to recover from pointer type erasure. Not for casting a pointer to a different type. Again, in this case it's safe because the new UInt32 pointer type is related to and layout compatible with a homogeneous tuple of UInt32. If you "assume" the memory is bound to Int32 instead of UInt32 that would be undefined behavior as soon as you access the pointer. So it's a dangerous abuse of the API, but I think it makes a bit more sense than calling bindMemory
.
@Lantua's answers are correct in this case, but layout compatibility is not enough. To avoid undefined behavior, aliasing pointer types also need to have a related type, which basically means one type needs to be a member of the other type. Swift doesn't have any special-case rules about related primitive types. Signed/unsigned types are unrelated.