Loads bits using native endianness when value spans multiple bytes.
On big endian architectures, bit_offset uses MSb 0 bit numbering.
On little endian architectures, bit_offset uses LSb 0 bit numbering.
See storeBits.
pub fn loadBits(comptime Int: type, buffer: []const Int, bit_offset: usize, comptime Result: type) Result
pub fn loadBits(comptime Int: type, buffer: []const Int, bit_offset: usize, comptime Result: type) Result {
const index = bit_offset / @bitSizeOf(Int);
const small_bit_offset = bit_offset % @bitSizeOf(Int);
const ResultInt = @Int(.unsigned, @bitSizeOf(Result));
switch (native_endian) {
.little => {
const result: ResultInt = @truncate(buffer[index] >> @intCast(small_bit_offset));
const available_bits = @bitSizeOf(Int) - small_bit_offset;
if (available_bits >= @bitSizeOf(ResultInt)) return @bitCast(result);
const missing_bits = @bitSizeOf(ResultInt) - available_bits;
const upper: ResultInt = @truncate(buffer[index + 1] & ((@as(usize, 1) << @intCast(missing_bits)) - 1));
return @bitCast(result | (upper << @intCast(available_bits)));
},
.big => {
const available_bits = @bitSizeOf(Int) - small_bit_offset;
if (available_bits >= @bitSizeOf(ResultInt)) {
const shift = available_bits - @bitSizeOf(ResultInt);
const result: ResultInt = @truncate(buffer[index] >> @intCast(shift));
return @bitCast(result);
}
const mask = (@as(Int, 1) << @intCast(available_bits)) - 1;
const result: ResultInt = @intCast(buffer[index] & mask);
const missing_bits = @bitSizeOf(ResultInt) - available_bits;
const lower: ResultInt = @truncate(buffer[index + 1] >> @intCast(@bitSizeOf(Int) - missing_bits));
return @bitCast((result << @intCast(missing_bits)) | lower);
},
}
}