UnsafeMutablePointer to [UInt8] without memory copy

后端 未结 2 1526
抹茶落季
抹茶落季 2021-02-05 23:15

Is it possible to create a [UInt8] from an UnsafeMutablePointer without copying the bytes?

In the NSData world I coul

相关标签:
2条回答
  • 2021-02-05 23:34

    You can use UnsafeBufferPointer + map to achieve your goal.
    KEEP IN MIND: pointer boundary should be maintained by yourself, while arrays will do by itself
    let bytesArray = UnsafeBufferPointer(start: bts, count: bytes.count).map{$0}
    Swift 5, Xcode 11:

    var bytes: [UInt8] = [1, 3, 5, 7]
    let count = bytes.count
    print(bytes)
    
    // MARK: - [UInt8] -> UnsafePointer<UInt8>
    
    // producing dangling pointer warning bug?
    let bts1: UnsafePointer<UInt8> = UnsafePointer(bytes)
    print(bts1, bts1[0], bts1[1], bts1[2], bts1[3], bts1[4])
    
    let bts = withUnsafePointer(to: &bytes[0]) {
        $0.withMemoryRebound(to: UInt8.self, capacity: count) { $0 }
    }
    print(bts, bts[0], bts[1], bts[4])
    
    // MARK: - UnsafePointer<UInt8> -> [UInt8]
    let bytesArray = UnsafeBufferPointer(start: bts, count: bytes.count).map{$0}
    print(bytesArray, bytesArray[0], bytesArray[1]/*, bytesArray[4]*/)
    

    output:

    [1, 3, 5, 7]
    0x0000600001946840 1 3 5 7 0
    0x0000600001946840 1 3 0
    [1, 3, 5, 7] 1 3
    

    bad samples:

    /// invalid sample 1
    let testA = withUnsafePointer(to: &bytes) {
        $0.withMemoryRebound(to: UInt8.self, capacity: count) { $0 }
    }
    print(testA, testA[0], testA[1], testA[4])
    
    /// invalid sample 2
    let testB = withUnsafePointer(to: bytes[0]) {
        $0.withMemoryRebound(to: UInt8.self, capacity: count) { $0 }
    }
    print(testB, testB[0], testB[1], testB[4])
    

    output:

    0x0000000102b4f520 32 104 0
    0x00007ffeed203ac0 192 58 254
    
    0 讨论(0)
  • 2021-02-06 00:00

    As already mentioned in the comments, you can create an UnsafeMutableBufferPointer from the pointer:

    let a = UnsafeMutableBufferPointer(start: p, count: n)
    

    This does not copy the data, which means that you have to ensure that the pointed-to data is valid as long as a is used. Unsafe (mutable) buffer pointers have similar access methods like arrays, such as subscripting:

    for i in 0 ..< a.count {
        print(a[i])
    }
    

    or enumeration:

    for elem in a {
        print(elem)
    }
    

    You can create a "real" array from the buffer pointer with

    let b = Array(a)
    

    but this will copy the data.

    Here is a complete example demonstrating the above statements:

    func test(_ p : UnsafeMutablePointer<UInt8>, _ n : Int) {
    
        // Mutable buffer pointer from data:
        let a = UnsafeMutableBufferPointer(start: p, count: n)
        // Array from mutable buffer pointer
        let b = Array(a)
    
        // Modify the given data:
        p[2] = 17
    
        // Printing elements of a shows the modified data: 1, 2, 17, 4
        for elem in a {
            print(elem)
        }
    
        // Printing b shows the orignal (copied) data: 1, 2, 3, 4
        print(b)
    
    }
    
    var bytes : [UInt8] = [ 1, 2, 3, 4 ]
    test(&bytes, bytes.count)
    
    0 讨论(0)
提交回复
热议问题