I'm trying to decode a protobuff encoded message, so I need to convert the first byte (the key) in the protobuff message into bits, so I can find the field number. How do I convert a UInt8 (the byte) into an array of bits?
Pseudo Code
private func findFieldNum(from byte: UInt8) -> Int {
//Byte is 0001 1010
var fieldNumBits = byte[1] ++ byte[2] ++ byte[3] ++ byte[4] //concatentates bits to get 0011
getFieldNum(from: fieldNumBits) //Converts 0011 to field number, 2^1 + 2^0 = 3
}
I saw this question, which converts an array of bits into array of bytes.
String, byte array. In Swift a byte is called a UInt8—an unsigned 8 bit integer. A byte array is a UInt8 array. In ASCII we can treat chars as UInt8 values. With the utf8 String property, we get a UTF8View collection.
Swift Convert String to Byte Array: utf8 and UInt8 Converts String to a byte array with the utf8 property. Convert the UInt8 array back into a String. String, byte array. In Swift a byte is called a UInt8—an unsigned 8 bit integer. A byte array is a UInt8 array.
In Swift a byte is called a UInt8—an unsigned 8 bit integer. A byte array is a UInt8 array. In ASCII we can treat chars as UInt8 values. With the utf8 String property, we get a UTF8View collection.
As [UInt8] is stored in a contiguous region of memory, there's no need to convert it to Data, pointer can access all bytes directly. Int 's byte order is little endian currently on all Apple platform, but this is not garanteed on other platforms. say we want [0, 0, 0, 0x0e] to convert to 14. (big-endian byte order)
Here's a basic function to get a Bit
array from a byte:
func bits(fromByte byte: UInt8) -> [Bit] {
var byte = byte
var bits = [Bit](repeating: .zero, count: 8)
for i in 0..<8 {
let currentBit = byte & 0x01
if currentBit != 0 {
bits[i] = .one
}
byte >>= 1
}
return bits
}
Here, Bit
is a custom enum type that I have defined as follows:
enum Bit: UInt8, CustomStringConvertible {
case zero, one
var description: String {
switch self {
case .one:
return "1"
case .zero:
return "0"
}
}
}
With this setup, the output of the following code:
let byte: UInt8 = 0x1f
print(bits(fromByte: byte))
would be:
[1, 1, 1, 1, 1, 0, 0, 0]
Improving on mohak's answer. With a generic function or an extension to cater for more than just UInt8
.
enum Bit: UInt8, CustomStringConvertible {
case zero, one
var description: String {
switch self {
case .one:
return "1"
case .zero:
return "0"
}
}
}
func bits<T: FixedWidthInteger>(fromBytes bytes: T) -> [Bit] {
// Make variable
var bytes = bytes
// Fill an array of bits with zeros to the fixed width integer length
var bits = [Bit](repeating: .zero, count: T.bitWidth)
// Run through each bit (LSB first)
for i in 0..<T.bitWidth {
let currentBit = bytes & 0x01
if currentBit != 0 {
bits[i] = .one
}
bytes >>= 1
}
return bits
}
extension FixedWidthInteger {
var bits: [Bit] {
// Make variable
var bytes = self
// Fill an array of bits with zeros to the fixed width integer length
var bits = [Bit](repeating: .zero, count: self.bitWidth)
// Run through each bit (LSB first)
for i in 0..<self.bitWidth {
let currentBit = bytes & 0x01
if currentBit != 0 {
bits[i] = .one
}
bytes >>= 1
}
return bits
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With