Alternative #1: use .pointee
property of UnsafePointer
As described in the following Q&A
you can use, in Swift 2.2, e.g.
UnsafePointer<UInt16>(bytes).memory
to convert a 2-byte UInt8
array to a UInt16
value (host byte order).
Now, in Swift 3.0-dev .memory
has been replaced by .pointee
. Applying the above as well as this change, we can likewise use UnsafePointer<UInt32>(bytes).pointee
to access the UInt32
representation of a 4-byte UInt8
array, however noting that the representation uses host byte order for conversion. To possible (if necessary) convert this to the big endian representation of the integer, we can use the .bigEndian
property available to each integer type, as described in the following Q&A:
This is still valid in Swift 3.0-dev, and consequently, we can construct your getUInt32BE(...)
method as follows
extension Collection where Iterator.Element == UInt8 {
public func getUInt32BE(at: Index.Distance) -> UInt32? {
let from = startIndex.advanced(by: at, limit: endIndex)
let to = from.advanced(by: 4, limit: endIndex)
guard case let bytes = Array(self[from..<to])
where bytes.count == 4 else { return nil }
return UnsafePointer<UInt32>(bytes).pointee.bigEndian
}
}
Alternative #2: use bit shifting
Alternatively, using a modified version of the above with bit shifting (similar to the attempt of your question) rather than using UnsafePointer<..>
:
extension Collection where Iterator.Element == UInt8 {
public func getUInt32BE(at: Index.Distance) -> UInt32? {
let from = startIndex.advanced(by: at, limit: endIndex)
let to = from.advanced(by: 4, limit: endIndex)
guard case let bytesSlice = self[from..<to]
where from.distance(to: to) == 4 else { return nil }
return bytesSlice.reduce(0) { (tot, val) -> UInt32 in
tot << 8 + UInt32(val as! UInt8)
}
}
}
Note that we need to help out the compiler by forcibly casting val
from Iterator.Element
to UInt8
(which is guaranteed to succeed due to the where
clause of the extension; Iterator.Element == UInt8
).
Example usage
Example usage for any of the two alternatives above:
/* example usage */
let bytes: [UInt8] = [
0, // 0b 0000 0000
255, // 0b 1111 1111
0, // 0b 0000 0000
104, // 0b 0110 1000
76] // 0b 0100 1100
/* byteArr[1..<5], big-endian:
0b 1111 1111 0000 0000 0110 1000 0100 1100 */
let u32verify = 0b11111111000000000110100001001100
print(u32verify) // 4278216780
if let u32val = bytes.getUInt32BE(1) {
print(u32val) // 4278216780, OK
}
For details on the Collection
protocol (the reason of your error above is not using the associated type Index.Distance
of this protocol to construct your sub-array), see e.g.