var tuple: (Int8, Int8, Int8, Int8, Int8) = (0,0,0,0,0)
let str = "abcdefghijk"
let _: Void = withUnsafeMutableBytes(of: &tuple) { ptr -> Void in
str.utf8CString.withUnsafeBytes { strPtr -> Void in
ptr.baseAddress!.copyMemory(from: strPtr.baseAddress!,
byteCount: min(strPtr.count, ptr.count))
}
}
print(tuple)
I’m using the old version of Swift that is on the iPad Playground App, but I think in Swift 5 String.utf8 has a direct “withUnsafeBufferPointer” method you can use.
EDIT: Oh, I didn’t see the version above, but this way avoids the intermediate Array.
It’s documented that the pointer value from withMemoryRebound is only valid within the closure... in practice however it still works, so I don’t know if you want to take that into consideration.
The biggest trouble is going to be initialising a 256-byte tuple. It’s probably best to write a little C shim for that.
You can do it from Swift, but it’s pretty ugly and doesn’t get optimised well.
typealias BigTuple = (Int8,Int8,Int8,Int8,Int8,Int8,Int8)
let BigTupleSize = 7
let p = UnsafeMutablePointer<BigTuple>.allocate(capacity: 1)
p.withMemoryRebound(to: Int8.self, capacity: BigTupleSize) { p2 in p2.assign(repeating: 0, count: BigTupleSize) }
// we’re relying on value semantics to make the compiler copy an
// independent tuple out of the memory we just allocated.
let tup = p[0]
p.deallocate()
print(tup)
I really wouldn't recommend relying on that. Unlike C, Swift only guarantees variable lifetime up to their last usage within a scope, and not necessarily to the very end of the scope.
Smuggling out the pointer from withMemoryRebound is dangerous because there's nothing telling the compiler that the lifetime of that memory should extend beyond the call to withMemoryRebound. Luckily, in this context, the lifetime of the memory is being preserved by the enclosing withUnsafeMutablePointer(to:_:).
If you wanted to do this, I would document it with a comment, because it's the kind of thing that very easily starts off being correct, but might eventually end up being mistakenly refactored in a way that breaks it.
Please don't use the approach suggested by @suyashsrijan's current comment (at time of writing). This code is trivially vulnerable to buffer overflows when used with strings whose length is not known at compile time, and doesn't generalise.
@Karl's suggestion, possibly use of .utf8 to get the collection, is better as it explicitly bounds the length of the copy. The cleanest version of this code as of Swift 5.1 is this:
var tuple: (Int8, Int8, Int8, Int8, Int8) = (0,0,0,0,0)
let str = "abcdefghijk"
withUnsafeMutableBytes(of: &tuple) { ptr in
ptr.copyBytes(from: str.utf8.prefix(ptr.count))
}
Note that this will not null-terminate the tuple. If you need to do that, you should unconditionally write a zero byte into the tuple's last entry, or preserve the the final entry by using a slightly shorter prefix.