Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert a double into a byte array in swift?

I know how to do it in java (see here), but I couldn't find a swift equivalent for java's ByteBuffer, and consequently its .putDouble(double value) method.

Basically, I'm looking for a function like this:
func doubleToByteArray(value: Double) -> [UInt8]? {
    . . .
}
doubleToByteArray(1729.1729) // should return [64, 155, 4, 177, 12, 178, 149, 234]
like image 998
Panini Raman Avatar asked Nov 16 '14 03:11

Panini Raman


3 Answers

typealias Byte = UInt8

func toByteArray<T>(var value: T) -> [Byte] {
    return withUnsafePointer(&value) {
        Array(UnsafeBufferPointer(start: UnsafePointer<Byte>($0), count: sizeof(T)))
    }
}

toByteArray(1729.1729)
toByteArray(1729.1729 as Float)
toByteArray(1729)
toByteArray(-1729)

But the results are reversed from your expectations (because of endianness):

[234, 149, 178, 12, 177, 4, 155, 64]
[136, 37, 216, 68]
[193, 6, 0, 0, 0, 0, 0, 0]
[63, 249, 255, 255, 255, 255, 255, 255]

Added:

func fromByteArray<T>(value: [Byte], _: T.Type) -> T {
    return value.withUnsafeBufferPointer {
        return UnsafePointer<T>($0.baseAddress).memory
    }
}

let a: Double = 1729.1729
let b = toByteArray(a) // -> [234, 149, 178, 12, 177, 4, 155, 64]
let c = fromByteArray(b, Double.self) // -> 1729.1729

For Xcode8/Swift3.0:

func toByteArray<T>(_ value: T) -> [UInt8] {
    var value = value
    return withUnsafePointer(to: &value) {
        $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<T>.size) {
            Array(UnsafeBufferPointer(start: $0, count: MemoryLayout<T>.size))
        }
    }
}

func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
    return value.withUnsafeBufferPointer {
        $0.baseAddress!.withMemoryRebound(to: T.self, capacity: 1) {
            $0.pointee
        }
    }
}

For Xcode8.1/Swift3.0.1

func toByteArray<T>(_ value: T) -> [UInt8] {
    var value = value
    return withUnsafeBytes(of: &value) { Array($0) }
}

func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
    return value.withUnsafeBytes {
        $0.baseAddress!.load(as: T.self)
    }
}
like image 127
rintaro Avatar answered Oct 14 '22 06:10

rintaro


Well, it wasn't easy, but here it is:

func doubleToByteArray(value: Double) -> [UInt8] {
    let count = sizeof(Double)
    var doubles: [Double] = [value]
    let data = NSData(bytes: doubles, length: count)
    var result = [UInt8](count: count, repeatedValue: 0)
    data.getBytes(&result, length: count)
    return result
}

Use with caution.

like image 24
vacawama Avatar answered Oct 14 '22 07:10

vacawama


Here's my updated version to the original solution.

/// input: array of bytes 
/// -> get pointer to byte array (UnsafeBufferPointer<[Byte]>)
/// -> access its base address
/// -> rebind memory to target type T (UnsafeMutablePointer<T>)
/// -> extract and return the value of target type
func binarytotype <T> (_ value: [Byte], _: T.Type) -> T
{
    return value.withUnsafeBufferPointer {
        $0.baseAddress!
          .withMemoryRebound(to: T.self, capacity: 1) {
            $0.pointee
        }
    }
}

/// input type: value of type T
/// -> get pointer to value of T
/// -> rebind memory to the target type, which is a byte array
/// -> create array with a buffer pointer initialized with the     source pointer
/// -> return the resulted array
func typetobinary <T> (_ value: T) -> [Byte]
{
    var mv : T = value
    let s : Int = MemoryLayout<T>.size
    return withUnsafePointer(to: &mv) {
        $0.withMemoryRebound(to: Byte.self, capacity: s) {
            Array(UnsafeBufferPointer(start: $0, count: s))
        }
    }
}

PS: Don't forget to replace Byte with UInt8.

like image 34
segabor Avatar answered Oct 14 '22 07:10

segabor