1

I'd like to access the raw bytes in Data as an array of numeric types for quick parsing. I have lots of data to parse, so I'm looking for efficiency. Data is a mix of shorts, ints, longs, and doubles.

The below code seems to work and be fast, but I'm getting deprecated warning: 'withUnsafeBytes' is deprecated

I can't figure out the updated way to treat the underlying bytes as an array of numbers for quick lookup.

    var data: Data = ...
            
    // create "virtual" arrays of different types to directly access bytes (without copying bytes)
    
    let ushortArray: [UInt16] = data.withUnsafeBytes {
        [UInt16](UnsafeBufferPointer(start: $0, count: data.count/2))
    }
    let intArray: [Int32] = data.withUnsafeBytes {
        [Int32](UnsafeBufferPointer(start: $0, count: data.count/4))
    }

    // Access data simply
    var i1: UInt16 = ushortArray[0]
    var i2: Int32 = intArray[1]

P.S. I'm not concerned with big/little endian

2
  • 1
    stackoverflow.com/questions/55378409/… ? I guess, I'm no sure yet that it's be then in the closure { $0.load(as: [UInt16].self) }, to test... Commented Mar 5, 2022 at 18:35
  • 1
    @Larme This only works for UInt16.self. For array AFAIR you need bindMemory Commented Mar 5, 2022 at 19:12

1 Answer 1

4

If you want to load it as an Array what you need is to use UnsafeRawBufferPointer bindMemorymethod to the type you want. you can also extend ContiguousBytes to make a generic method and simplify your syntax:

Note: if you are planing to get a subsequence of your data make sure to do NOT subscript the data to avoid misaligned errors. You need to use Data subdata method instead.

extension ContiguousBytes {
    func objects<T>() -> [T] { withUnsafeBytes { .init($0.bindMemory(to: T.self)) } }
    var uInt16Array: [UInt16] { objects() }
    var int32Array: [Int32] { objects() }
}

extension Array {
    var data: Data { withUnsafeBytes { .init($0) } }
}

Usage:

let uInt16Array: [UInt16] = [.min, 1, 2, 3, .max]  // [0, 1, 2, 3, 65535]
let int32Array: [Int32] = [.min, 1, 2, 3, .max]    // [-2147483648, 1, 2, 3, 2147483647]

let uInt16ArrayData = uInt16Array.data  // 10 bytes
let int32ArrayData = int32Array.data    // 20 bytes

let uInt16ArrayLoaded = uInt16ArrayData.uInt16Array  // [0, 1, 2, 3, 65535]
let int32ArrayLoaded = int32ArrayData.int32Array       // [-2147483648, 1, 2, 3, 2147483647]

// Access data simply
let i1 = uInt16ArrayLoaded[0]   //  UInt16 0
let i2 = int32ArrayLoaded[0]    // Int32 -2147483648
let i3 = uInt16ArrayLoaded[4]   //  UInt16 65535
let i4 = int32ArrayLoaded[4]    // Int32 2147483647
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.