agelter
agelter

Reputation: 331

How to do memcmp() in Swift?

I'm trying to convert some of my code from Objective-C to Swift. One method that I'm having trouble with does a comparison of a CBUUID with an UInt16. This was fairly straight-forward in Objective-C, but I'm having a hard time coming up with a good way to do this in Swift.

Here's the Objective-C version:

/*
 *  @method compareCBUUIDToInt
 *
 *  @param UUID1 UUID 1 to compare
 *  @param UUID2 UInt16 UUID 2 to compare
 *
 *  @returns 1 (equal) 0 (not equal)
 *
 *  @discussion compareCBUUIDToInt compares a CBUUID to a UInt16 representation of a UUID and returns 1
 *  if they are equal and 0 if they are not
 *
 */
-(int) compareCBUUIDToInt:(CBUUID *)UUID1 UUID2:(UInt16)UUID2 {
    char b1[16];
    [UUID1.data getBytes:b1];
    UInt16 b2 = [self swap:UUID2];
    if (memcmp(b1, (char *)&b2, 2) == 0) return 1;
    else return 0;
}

My (untested) version of this method in Swift got much more complicated and I'm hoping that I'm just missing some better ways to use the language:

func compareCBUUID(CBUUID1: CBUUID, toInt CBUUID2: UInt16) -> Int {
    let uuid1data = CBUUID1.data
    let uuid1count = uuid1data.length / sizeof(UInt8)
    var uuid1array = [UInt8](count: uuid1count, repeatedValue: 0)
    uuid1data.getBytes(&uuid1array, length: uuid1count * sizeof(UInt8))

    // @todo there's gotta be a better way to do this
    let b2: UInt16 = self.swap(CBUUID2)
    var b2Array = [b2 & 0xff, (b2 >> 8) & 0xff]
    if memcmp(&uuid1array, &b2Array, 2) == 0 {
        return 1
    }
    return 0
}

There are two things that seem to complicate things. First, it isn't possible to declare a fixed sized buffer in Swift, so the char b1[16] in ObjC becomes 3 lines in Swift. Second, I don't know of a way to do a memcmp() in Swift with a UInt16. The compiler complains that:

'UInt16' is not convertible to '@value inout $T5'

So that's where the clunky step comes in where I separate out the UInt16 into a byte array by hand.

Any suggestions?

Upvotes: 4

Views: 1569

Answers (1)

Martin R
Martin R

Reputation: 539705

The corresponding Swift code for char b1[16] would be

var b1 = [UInt8](count: 16, repeatedValue: 0)

and for the byte swapping you can use the "built-in" method byteSwapped or bigEndian. Casting the pointer for memcpy() is a bit tricky.

The direct translation of your Objective-C code to Swift would be (untested!):

var b1 = [UInt8](count: 16, repeatedValue: 0)
CBUUID1.data.getBytes(&b1, length: sizeofValue(b1))
var b2: UInt16 = CBUUID2.byteSwapped
// Perhaps better:
// var b2: UInt16 = CBUUID2.bigEndian
if memcmp(UnsafePointer(b1), UnsafePointer([b2]), 2) == 0 {
    // ...
}

However, if you define b1 as an UInt16 array then you don't need memcmp() at all:

var b1 = [UInt16](count: 8, repeatedValue: 0)
CBUUID1.data.getBytes(&b1, length: sizeofValue(b1))
var b2: UInt16 = CBUUID2.bigEndian
if b1[0] == b2 {
    // ...
}

Upvotes: 2

Related Questions