arraysswiftswift4.2unsafemutablepointer

Casting between Swift array types without copy or allocations


I want to access an existing array of UInt64 as if it is an array of Int8. Key requirement is efficiency - I don't want to copy or reallocate the data, just have direct access. I don't want side effects (for example I want to be able to continue to use the uint64Array after this block of code has executed, was reading about rebinding having undefined side effects.)

I tried doing this with Swift 4.2:

var uint64Array = [UInt64](repeating: 0, count: 100)

uint64Array.withUnsafeMutableBufferPointer() {
    uint64Pointer in
    uint64Pointer.withMemoryRebound(to: Int8.self) {   // <- Error occurs here.
        int8Pointer in
        int8Pointer[0] = 1
        int8Pointer[1] = 2
        int8Pointer[2] = 3
        int8Pointer[3] = 4
    }
}

However I get a Fatal Error at runtime on the following line:

    uint64Pointer.withMemoryRebound(to: Int8.self) {

Is this the right approach? If so, why am I getting the Fatal Error?


Solution

  • I think the problem is that you can't bind to a different type directly as per this note in the docs:

    Only use this method to rebind the buffer’s memory to a type with the same size and stride as the currently bound Element type. To bind a region of memory to a type that is a different size, convert the buffer to a raw buffer and use the bindMemory(to:) method.

    If bytes is what you're after then the quickest route is:

    var uint64Array = [UInt64](repeating: 0, count: 100)
    uint64Array.withUnsafeMutableBytes { x in
    
        x[0] = 1
        x[1] = 2
        x[3] = 3
        x[4] = 4
    
    }
    

    If you have another type you'd like to use you can do it like this:

    var uint64Array = [UInt64](repeating: 0, count: 100)
    
    uint64Array.withUnsafeMutableBufferPointer() {
        uint64Pointer in
    
        let x = UnsafeMutableRawBufferPointer(uint64Pointer).bindMemory(to: Int32.self)
        x[0] = 1
        x[1] = 2
        x[3] = 3
        x[4] = 4
    
    }