We can generalize @eskimo's solution a bit if we want (perhaps too much) to work with any iterator or collection of UInt8
and any FixedWidthInteger
type:
extension FixedWidthInteger {
init<I>(littleEndianBytes iterator: inout I)
where I: IteratorProtocol, I.Element == UInt8 {
self = stride(from: 0, to: Self.bitWidth, by: 8).reduce(into: 0) {
$0 |= Self(truncatingIfNeeded: iterator.next()!) &<< $1
}
}
init<C>(littleEndianBytes bytes: C) where C: Collection, C.Element == UInt8 {
precondition(bytes.count == (Self.bitWidth+7)/8)
var iter = bytes.makeIterator()
self.init(littleEndianBytes: &iter)
}
}
Even in this ridiculous generality, Swift generates basically optimal code with optimization enabled, which I think is pretty cool:
func foo(_ bytes: [UInt8]) -> UInt32 {
return UInt32(littleEndianBytes: bytes)
}
output.foo([Swift.UInt8]) -> Swift.UInt32:
push rbp // setup stack frame
mov rbp, rsp
cmp qword ptr [rdi + 16], 4 // check count == 4
jne .LBB6_1
mov eax, dword ptr [rdi + 32] // 4-byte load from array
pop rbp // tear down stack frame
ret
.LBB6_1:
ud2 // trap if count != 4