[swift-users] Guarantees of Tuples as Fixed Sized (stack allocated) Arrays
Johannes Weiss
johannesweiss at apple.com
Fri Apr 28 08:31:05 CDT 2017
Hi Martin,
> On 28 Apr 2017, at 12:59, Martin R <martinr448 at gmail.com> wrote:
>
> As far as I know, the only guarantee is made for structures imported from C. From https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160516/001968.html :
>
> Swift structs have unspecified layout. If you depend on a specific layout, you should define the struct in C and import it into Swift for now.
Thanks! Yes I know structs have unspecified layout but that doesn't necessarily mean tuples have that too. Especially if you consider that C structs having fixed sized arrays in them get imported as tuples. See for example this:
typedef struct __siginfo {
int si_signo; /* signal number */
int si_errno; /* errno association */
int si_code; /* signal code */
pid_t si_pid; /* sending process */
uid_t si_uid; /* sender's ruid */
int si_status; /* exit value */
void *si_addr; /* faulting instruction */
union sigval si_value; /* signal value */
long si_band; /* band event for SIGPOLL */
unsigned long __pad[7]; /* Reserved for Future Use */
} siginfo_t;
gets imported as
--- SNIP ---
public struct __siginfo {
public var si_signo: Int32 /* signal number */
public var si_errno: Int32 /* errno association */
public var si_code: Int32 /* signal code */
public var si_pid: pid_t /* sending process */
public var si_uid: uid_t /* sender's ruid */
public var si_status: Int32 /* exit value */
public var si_addr: UnsafeMutableRawPointer! /* faulting instruction */
public var si_value: sigval /* signal value */
public var si_band: Int /* band event for SIGPOLL */
public var __pad: (UInt, UInt, UInt, UInt, UInt, UInt, UInt) /* Reserved for Future Use */
public init()
public init(si_signo: Int32, si_errno: Int32, si_code: Int32, si_pid: pid_t, si_uid: uid_t, si_status: Int32, si_addr: UnsafeMutableRawPointer!, si_value: sigval, si_band: Int, __pad: (UInt, UInt, UInt, UInt, UInt, UInt, UInt))
}
public typealias siginfo_t = __siginfo
--- SNAP ---
So the `unsigned long __pad[7]` becomes `public var __pad: (UInt, UInt, UInt, UInt, UInt, UInt, UInt)`
and given that, this should really be legal, right?
var random_uint_7_tuple: (UInt, UInt, UInt, UInt, UInt, UInt, UInt) = (1, 2, 3, 4, 5, 6, 7)
var si = siginfo_t()
_ = withUnsafeMutablePointer(to: &si.__pad) { (si_pad_ptr) -> Void in
return withUnsafeMutablePointer(to: &random_uint_7_tuple) { (tuple_ptr) -> Void in
si_pad_ptr.assign(from: tuple_ptr, count: 1)
}
}
from this example I believe we can see that the Swift values of type `(UInt, UInt, UInt, UInt, UInt, UInt, UInt)` MUST have the same layout as `unsigned long[7]` imported from C, right? withUnsafeMutablePointer() to those values gives me a UnsafeMutablePointer<(UInt, UInt, UInt, UInt, UInt, UInt, UInt)> in both cases.
That's why I think inducing unspecified tuple layout from unspecified struct layout doesn't work. Structs are nominal types (so I can't recreate the same type that was imported from C in pure Swift. Tuples on the other hand are structural types which means I am able to recreate the same type that is imported from C in Swift (which is what I did in the example above).
Does that make sense?
Cheers,
Johannes
>
> and from https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160516/001980.html :
>
> That's not necessary. You can leave the struct defined in C and import it into Swift. Swift will respect C's layout.
>
> Regards, Martin
>
>
>> On 28. Apr 2017, at 13:03, Johannes Weiss via swift-users <swift-users at swift.org> wrote:
>>
>> Hi swift-users,
>>
>> (sorry for the cross post to swift-dev, but wasn't sure where it belongs)
>>
>> I tried to find guarantees about the memory layout Swift tuples but couldn't find anything. The reason I ask is because I'd like to use them as fixed sized (stack allocated) arrays. I'm pretty sure they're actually not guaranteed to be stack allocated but highly likely I assume :).
>>
>> Am I correct in assuming that
>>
>> let swift_events: (kevent, kevent) = ...
>>
>> has the same memory layout as
>>
>> struct kevent c_events[2] = ...
>>
>> ? In other words, is this legal:
>>
>> var events = (kevent(), kevent())
>> withUnsafeMutableBytes(of: &events) { event_ptr in
>> precondition(MemoryLayout<kevent>.size * 2 == event_ptr.count)
>> if let ptr = event_ptr.baseAddress?.bindMemory(to: kevent.self, capacity: 2) {
>> return kevent(someFileDescriptor, ptr, 2, ptr, 2, nil)
>> }
>> }
>>
>> I'm assuming yes but I'd like to make sure.
>>
>> Many thanks,
>> Johannes
>>
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
>
More information about the swift-users
mailing list