(String, String) is a nontrivial object; since buffer is uninitialized when the closure begins, you have to use:
buffer.initializeElement(at: count, to: (value1, value2))
instead of
buffer[count] = (value1, value2)
in order to initialize it. You can avoid this by restricting yourself to safe Swift:
func tuples(_ values: [String]) -> [(String, String)] {
(0 ..< values.count/2).map { i in (values[2*i], values[2*i+1]) }
}
or possibly by using chunks(ofCount:) from Swift Algorithms, though this has slightly different behavior when there are an odd number of elements in values.
The unfortunately nonobvious issue here is that you are operating on uninitialized memory, but using MutableCollection API. UnsafeMutableBufferPointer's collection API is only valid for initialized memory.
We are proposing an API addition where the uninitialized memory is represented by an OutputSpan:
Ah that makes complete sense, thank you. Is there no way we could get a diagnostic to recognise this as an issue? Although if we can get a version of Array(unsafeUninitializedCapacity:) that uses OutputSpan I'd probably move to that in the future.
That’s the problem with unsafe pointers: the compiler is unable to help with their many states. There might be a way to improve this, but the effort is better spent on expanding the reach of safe abstractions.
It might be worth making the unsafeUninitializedCapacity: methods fill the memory with a somewhat unique sentinel value (endless screaming, 0xaaaa...aaaa) in debug builds, but yeah, we really want to move people off of these and onto OutputSpan, and just define most of these problems away.
Tangentially, are we expecting to provide a safe version of unsafeTemporaryAllocation(of:capacity:) that provides an OutputSpan? Because I would be very interested in such a thing.
There's a compiler issue that prevents us from providing typed-throws variants of the withUnsafeTemporaryAllocation() functions, and that issue made me discount the idea of pursuing the safe withTemporaryAllocation(). However, that's wrong! We could and should implement a saferthrows/rethrows version and generalize it later when the compiler supports it.