#ifndef BITBUFF_H #define BITBUFF_H /* ========================== * * Bitbuff * ========================== */ struct bitbuff { b32 is_backed_by_arena; /* If `is_arena_bitbuff` is 1, this dynamically-sized arena will be used for reading & writing (meaning writing cannot overflow) */ struct arena *arena; /* If `is_arena_bitbuff` is 0, this fixed-sized buffer willl be used for reading & writing */ struct string fixed_buffer; }; struct bitbuff bitbuff_alloc(u64 arena_reserve); void bitbuff_release(struct bitbuff *bitbuff); struct bitbuff bitbuff_from_string(struct string s); /* ========================== * * Writer * ========================== */ /* NOTE: base_len is not stored in writer (as it is in the reader) since a dynamic arena-backed bitbuff could grow meaning len needs to be re-checked */ struct bitbuff_writer { b32 overflowed; struct bitbuff *bb; u8 *base; u64 cur_bit; #if BITBUFF_DEBUG b32 debug_enabled; #endif }; struct bitbuff_writer bw_from_bitbuff(struct bitbuff *bb); struct bitbuff_writer bw_from_bitbuff_no_debug(struct bitbuff *bb); u64 bw_num_bits_written(struct bitbuff_writer *bw); u64 bw_num_bytes_written(struct bitbuff_writer *bw); struct string bw_get_written(struct arena *arena, struct bitbuff_writer *bw); u8 *bw_get_written_raw(struct bitbuff_writer *bw); b32 bw_check_overflow_bits(struct bitbuff_writer *bw, u64 num_bits); void bw_align(struct bitbuff_writer *bw); void bw_write_ubits(struct bitbuff_writer *bw, u64 value, u8 num_bits); void bw_write_ibits(struct bitbuff_writer *bw, i64 value, u8 num_bits); b32 bw_write_bit(struct bitbuff_writer *bw, u8 value); void bw_write_uv(struct bitbuff_writer *bw, u64 value); void bw_write_iv(struct bitbuff_writer *bw, i64 value); void bw_write_f32(struct bitbuff_writer *bw, f32 value); void bw_write_f64(struct bitbuff_writer *bw, f64 value); void bw_write_uid(struct bitbuff_writer *bw, struct uid value); void bw_write_string(struct bitbuff_writer *bw, struct string s); void bw_write_bytes(struct bitbuff_writer *bw, struct string bytes); #if BITBUFF_DEBUG void bw_write_dbg_marker(struct bitbuff_writer *bw, struct string name); #else #define bw_write_dbg_marker(bw, name) #endif /* ========================== * * Reader * ========================== */ struct bitbuff_reader { b32 overflowed; u64 base_len; u8 *base; u64 cur_bit; #if BITBUFF_DEBUG b32 debug_enabled; #endif }; struct bitbuff_reader br_from_bitbuff(struct bitbuff *bb); struct bitbuff_reader br_from_bitbuff_no_debug(struct bitbuff *bb); u64 br_cur_bit(struct bitbuff_reader *br); u64 br_cur_byte(struct bitbuff_reader *br); u64 br_num_bits_left(struct bitbuff_reader *br); u64 br_num_bytes_left(struct bitbuff_reader *br); b32 br_check_overflow_bits(struct bitbuff_reader *br, u64 num_bits); void br_align(struct bitbuff_reader *br); u64 br_read_ubits(struct bitbuff_reader *br, u8 num_bits); i64 br_read_ibits(struct bitbuff_reader *br, u8 num_bits); u8 br_read_bit(struct bitbuff_reader *br); u64 br_read_uv(struct bitbuff_reader *br); i64 br_read_iv(struct bitbuff_reader *br); f32 br_read_f32(struct bitbuff_reader *br); f64 br_read_f64(struct bitbuff_reader *br); struct uid br_read_uid(struct bitbuff_reader *br); struct string br_read_string(struct arena *arena, struct bitbuff_reader *br); void br_read_bytes(struct bitbuff_reader *br, struct string dst); u8 *br_read_bytes_raw(struct bitbuff_reader *br, u64 num_bytes); void br_seek_bytes(struct bitbuff_reader *br, u64 num_bytes); void br_seek_to_byte(struct bitbuff_reader *br, u64 pos); #if BITBUFF_DEBUG void br_read_dbg_marker(struct bitbuff_reader *br, struct string name); #else #define br_read_dbg_marker(br, name) #endif #if BITBUFF_TEST void bitbuff_test(void); #endif #endif