0

I just want call C function

static  inline  uint64_t  wyhash(const void* key,  uint64_t  len, uint64_t  seed)

from Swift like that

func hash<T: Any>(key: T, seed: UInt64) -> UInt64 { wyhash(...) }

Is it possible? And how?

jeudesprits
  • 45
  • 1
  • 4

1 Answers1

1

To compute the size, use MemoryLayout:

func hash<T>(key: T, seed: UInt64) -> UInt64 {
    let len = UInt64(MemoryLayout.size(ofValue: key))
    return withUnsafePointer(to: key) { myhash($0, len, seed) }
}

Keep in mind that structural types may have internal padding, and I don't believe Swift promises that to be initialized. So you may wind up hashing random values if you're not careful what you pass here. And of course types may have non-obvious internal state that can cause "equal" values to hash differently or vice versa. Given the likelihood of difficult-to-diagnose bugs, I would typically suggest writing specific overloads for types you know are acceptable to this function rather than trying to hash over Any. At a minimum, I'd constrain T to some protocol (with no syntactic requirements) that expresses "I've checked that this type is myhash-able."

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thx! But `UInt64(MemoryLayout.size(ofValue: key))` for example `[Int]` with 3 elements give 8. Shouldn't it be 3 *8 ? – jeudesprits Nov 15 '19 at 18:26
  • No, and this is exactly my point. `Array` has exactly one internal property, a buffer, which is a reference type, so the size of an Array is exactly one pointer size. https://github.com/apple/swift/blob/master/stdlib/public/core/Array.swift#L299-L318 Array has various interfaces (`withUnsafe...`) that direct memory access to that buffer, but Array *itself* only contains a pointer. – Rob Napier Nov 15 '19 at 18:52
  • Note that Array can also be a thin wrapper around other types, most notably an NSArray. So there's no promise that even the buffer is laid out in contiguous memory. If you pass an Array to a C function directly (as an Array, rather than generically as a T), then the compiler will make sure it all works out, even if that requires some copying to get everything laid out correctly. But you can't just pass "any type T" and expect it to be shuffled around to look like a `void*` in a meaningful and consistent way. – Rob Napier Nov 15 '19 at 19:11
  • (Even what I've said here isn't always true. The buffer may be a value type in some cases, and may be inlined on the stack. You just don't know in the general case.) – Rob Napier Nov 15 '19 at 19:14