我可以使用UnsafePointer.withMemoryRebound将[UInt8]重新映射到[UInt16]吗?

时间:2018-07-02 10:47:44

标签: arrays swift

我正在尝试将较大的[UInt8]重新映射为[UInt16],到目前为止,我的解决方案如下:

//Function that converts [UInt8] into [UInt16]
func foo(arr: [UInt8])->[UInt16]{
    //Split into even and odds
    let even = stride(from: 0, to: arr.count, by: 2).map { arr[$0] }
    let odd = stride(from: 1, to: arr.count, by: 2).map { arr[$0] }
    //pair each even with the next odd
    let paired=Array(zip(even, odd))
    //reduce UInt8 pairs to UInt16

    return paired.reduce([UInt16]()) { (acc, curr) -> [UInt16] in
        let u16 = UnsafePointer([curr.0, curr.1]).withMemoryRebound(to: UInt16.self, capacity: 1) {
            $0.pointee
        }
        var newV = acc
        newV.append(u16)
        return newV
    }
}

以上方法有效,但是效率很低。减少功能是大部分计算时间发生的地方。 我想知道是否可以直接使用UnsafePointer.withMemoryRebound重映射。 我尝试过:

let test : [UInt16] = UnsafePointer([UInt8(0), UInt8(1),UInt8(0), UInt8(1)]).withMemoryRebound(to: [UInt16].self, capacity: 2) { 
    $0.pointee 
} 

导致:

Execution interrupted. Enter code to recover and continue.
Enter LLDB commands to investigate (type :help for assistance.)
Process 57635 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x00007fff7d038d5f libobjc.A.dylib`objc_retain + 15
libobjc.A.dylib`objc_retain:
->  0x7fff7d038d5f <+15>: movq   (%rdi), %rax
    0x7fff7d038d62 <+18>: movabsq $0x7ffffffffff8, %rcx     ; imm = 0x7FFFFFFFFFF8 
    0x7fff7d038d6c <+28>: andq   %rax, %rcx
    0x7fff7d038d6f <+31>: testb  $0x2, 0x20(%rcx)
Target 0: (repl_swift) stopped.

也许我误解了它应该如何工作。能做到吗有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

我的建议是创建一个Data实例,并使用withUnsafeBytes重新映射字节。

let arr : [UInt8] = [0x31, 0x32, 0x33, 0x34]
let data = Data(arr)
let u16 = data.withUnsafeBytes {
    [UInt16](UnsafeBufferPointer(start: $0, count: data.count/MemoryLayout<UInt16>.stride))
} // [12849, 13363]

答案 1 :(得分:0)

使用withUnsafeBytes()方法访问数组的元素存储,该方法使用UnsafeRawBufferPointer调用闭包。现在可以将该指针 bound 绑定到所需类型UInt16的缓冲区指针。最终创建了新的阵列-这是唯一复制数据的地方。

let uint8Array: [UInt8] = [1, 2, 3, 4]
let uint16Array = uint8Array.withUnsafeBytes { ptr in
    Array(ptr.bindMemory(to: UInt16.self))
}

print(uint16Array) // [513, 1027]