1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-03 08:34:07 +02:00

optimize push_bits

This commit is contained in:
Robin Appelman 2020-02-15 14:08:54 +01:00
commit 123223f479
3 changed files with 29 additions and 69 deletions

View file

@ -6,24 +6,22 @@
Tools for reading data types of arbitrary bit length and might not be byte-aligned in the source data
The main way of handling with the binary data is to first create a `BitBuffer`
,wrap it into a `BitStream` and then read from the stream.
If performance is critical, working directly on the BitBuffer can be faster.
The main way of handling with the binary data is to first create a [`BitBuffer`]
,wrap it into a [`BitStream`] and then read from the stream.
Once you have a BitStream, there are 2 different approaches of reading data
- read primitives, Strings and byte arrays, using `read_bool`, `read_int`, `read_float`, `read_byes` and `read_string`
- read any type implementing the `BitRead` or `BitReadSized` traits using `read` and `read_sized`
- `BitRead` is for types that can be read without requiring any size info (e.g. null-terminated strings, floats, whole integers, etc)
- `BitReadSized` is for types that require external sizing information to be read (fixed length strings, arbitrary length integers
- read primitives, Strings and byte arrays, using [`read_bool`], [`read_int`], [`read_float`], [`read_bytes`] and [`read_string`]
- read any type implementing the [`BitRead`] or [`BitReadSized`] traits using [`read`] and [`read_sized`]
- [`BitRead`] is for types that can be read without requiring any size info (e.g. null-terminal strings, floats, whole integers, etc)
- [`BitReadSized`] is for types that require external sizing information to be read (fixed length strings, arbitrary length integers
The `BitRead` and `BitReadSized` traits can be used with `#[derive]` if all fields implement `BitRead` or `BitReadSized`.
The [`BitRead`] and [`BitReadSized`] traits can be used with `#[derive]` if all fields implement [`BitRead`] or [`BitReadSized`].
## Examples
```rust
use bitbuffer::{BitBuffer, LittleEndian, BitStream, BitRead};
use bitbuffer::{BitReadBuffer, LittleEndian, BitReadStream, BitRead};
#[derive(BitRead)]
struct ComplexType {
@ -33,16 +31,14 @@ struct ComplexType {
third: bool,
}
fn main() {
let bytes = vec![
0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
];
let buffer = BitBuffer::new(bytes, LittleEndian);
let mut stream = BitStream::new(buffer);
let buffer = BitReadBuffer::new(bytes, LittleEndian);
let mut stream = BitReadStream::new(buffer);
let value: u8 = stream.read_int(7)?;
let complex: ComplexType = stream.read()?;
}
```
## License

View file

@ -1,7 +1,6 @@
[![Crates.io](https://img.shields.io/crates/v/bitbuffer.svg)](https://crates.io/crates/bitbuffer)
[![Documentation](https://docs.rs/bitbuffer/badge.svg)](https://docs.rs/bitbuffer/)
[![Dependency status](https://deps.rs/repo/github/icewind1991/bitbuffer/status.svg)](https://deps.rs/repo/github/icewind1991/bitbuffer)
{{badges}}
# {{crate}}

View file

@ -98,58 +98,23 @@ where
/// Push up to an usize worth of bits
fn push_bits(&mut self, bits: usize, count: usize) {
debug_assert!(count < USIZE_BITS - 8);
let bit_offset = self.bit_len & 7;
let byte_count = (count + 7) / 8;
let last_written_byte = self.bytes.pop().unwrap_or(0);
let merged_byte_count = (count + bit_offset + 7) / 8;
if bit_offset == 0 {
if E::is_le() {
let merged = last_written_byte as usize | bits << bit_offset;
self.bytes
.extend_from_slice(&bits.to_le_bytes()[0..byte_count])
.extend_from_slice(&merged.to_le_bytes()[0..merged_byte_count]);
} else {
let bytes = (bits << (USIZE_BITS - bit_offset - count)).to_be_bytes();
self.bytes.extend_from_slice(&bytes[0..byte_count])
let merged = ((last_written_byte as usize) << (USIZE_BITS - 8))
| bits << (USIZE_BITS - bit_offset - count);
self.bytes
.extend_from_slice(&merged.to_be_bytes()[0..merged_byte_count]);
}
self.bit_len += count;
} else {
if E::is_le() {
let first_part_length = min(USIZE_SIZE - bit_offset, count);
let first_part = get_bits_from_usize::<E>(bits, 0, first_part_length) as u8;
let last_written_byte = self.bytes.pop().unwrap_or(0);
let merged_byte = last_written_byte | (first_part << bit_offset as u8);
self.bytes.push(merged_byte);
self.bit_len += first_part_length;
if first_part_length < count {
let second_part = get_bits_from_usize::<E>(
bits,
first_part_length,
count - first_part_length,
);
self.push_bits(second_part, count - first_part_length);
}
} else {
let first_part_length = min(USIZE_SIZE - bit_offset, count);
let first_part = get_bits_from_usize::<LittleEndian>(
bits,
count - first_part_length,
first_part_length,
) as u8;
let last_written_byte = self.bytes.pop().unwrap_or(0);
let merged_byte =
last_written_byte | first_part << (8 - bit_offset - first_part_length) as u8;
self.bytes.push(merged_byte);
self.bit_len += first_part_length;
if first_part_length < count {
let second_part =
get_bits_from_usize::<LittleEndian>(bits, 0, count - first_part_length);
self.push_bits(second_part, count - first_part_length);
}
}
}
}
/// Write a boolean into the buffer