[swift-users] Extracting arbitrary types (e.g. UInt16) out of Data

Charles Srstka cocoadev at charlessoft.com
Mon Jun 26 16:06:45 CDT 2017


> On Jun 26, 2017, at 3:47 PM, Roderick Mann <rmann at latencyzero.com> wrote:
> 
>> On Jun 26, 2017, at 10:20 , Charles Srstka <cocoadev at charlessoft.com> wrote:
>> 
>> Rats, I was hoping that one of the reasons about being so explicit what we’re going to access and where with bindMemory() and friends would be to take care of these sorts of issues.
>> 
>> In that case, the simplest way to do it is probably just this:
>> 
>> let crc = (UInt16(myData[myData.endIndex]) << 8) | UInt16(myData[myData.endIndex - 1])
> 
> By the way, self.endIndex == self.count, so shouldn't these both have an additional 1 subtracted?

Whoops, you’re right.

> That's what I'm seeing, and what the docs show. What's the point of endIndex? Completeness?

Short answer: Always use startIndex and endIndex, never, ever, *ever* use 0 or count.

Long answer:

- - - - -

import Foundation

let data = Data(bytes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
let slice = data[4..<8]

let firstTwo = slice[0..<2]
let lastTwo = slice[(slice.count - 2)..<slice.count]

print("firstTwo: \(firstTwo.map { $0 }), lastTwo: \(lastTwo.map { $0 })”)

- - - - -

What do you think the above will output?

If you said “[4, 5], then [6, 7]”, you’re wrong. On my machine, this outputs:

- - - - -

firstTwo: [0, 1], lastTwo: [4, 5]

- - - - -

Why the heck did that happen, you ask? Well, it’s because Data is its own slice, which means a Data made from another Data retains the indices *of its parent Data*, not of the slice. So when you called slice[0..<2], it returned the first two bytes *of the parent data*, which are 0 and 1. You might be wondering why it returned 4 and 5 for the last two bytes when those aren’t the 2nd and 3rd byte of either collection… I think it’s just because these out-of-range accesses are undefined behavior (on the latest version of the compiler from GitHub, these all crash).

Anyway, doing it with startIndex and endIndex actually gets you the values you expect.

Charles



More information about the swift-users mailing list