3

I'm trying to convert a ContiguousArray of Floats into a byte array in Swift but cannot find a smart way without using a for loop. I have been following previous posts such as How to convert a double into a byte array in swift?, but I am unable to retrieve the contents of the array without iteratively getting each element one by one.

Is there an elegant way to directly "copy" the bytes of a ContiguousArray directly to byte array?

PS: I have successfully implemented converting structures into byte arrays, but not able to do the same with arrays.

jiko
  • 146
  • 1
  • 9

1 Answers1

5

You can use the withUnsafeBytes() method to get a buffer pointer to the underlying bytes of the array's contiguous storage, and directly initialize an [UInt8] array from that buffer pointer. Example:

let floatArray: [Float] = [1.0, 2.0]
// Works also with a ContiguousArray:
// let floatArray: ContiguousArray<Float> = [1.0, 2.0]

let byteArray = floatArray.withUnsafeBytes { Array($0) }
print(byteArray) // [0, 0, 128, 63, 0, 0, 0, 64]

Equivalently (based on Leo's suggestion):

let byteArray = floatArray.withUnsafeBytes(Array.init)

The byte array contains the binary representation of the floating point numbers in host byte order (which is little-endian on all current Apple platforms). A conversion to big-endian is possible, but not without an intermediate copy to an integer array:

let floatArray: ContiguousArray<Float> = [1.0, 2.0]
let intArray = floatArray.map { $0.bitPattern.bigEndian }
let byteArray = intArray.withUnsafeBytes(Array.init)
print(byteArray) // 63, 128, 0, 0, 64, 0, 0, 0]

Reverse conversion: A simple method would be

let floatArray2 = byteArray.withUnsafeBytes { Array($0.bindMemory(to: Float.self)) }
print(floatArray2) // [1.0, 2.0]

However, that requires that the element storage of the byte array is properly aligned for floating point numbers. If that is not guaranteed then you can do

var floatArray2 = [Float](repeating: 0.0, count: byteArray.count / MemoryLayout<Float>.stride)
_ = floatArray2.withUnsafeMutableBytes { byteArray.copyBytes(to: $0) }
print(floatArray2) // [1.0, 2.0]
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382