pub struct BitmapManager;
pub const MAX_BITMAP_PAYLOAD_BYTES: usize = 512 * 1024 * 1024;
pub const MAX_OFFSET_FOR_BITMAP_LENGTH: i64 = (MAX_BITMAP_PAYLOAD_BYTES as i64 * 8) - 1;
impl BitmapManager {
#[inline(always)]
pub const fn is_valid_bit_offset(offset: i64) -> bool {
offset >= 0 && offset <= MAX_OFFSET_FOR_BITMAP_LENGTH
}
#[inline(always)]
pub const fn try_validate_length_in_bytes(offset: i64) -> Option<usize> {
if !Self::is_valid_bit_offset(offset) {
return None;
}
Some(((offset >> 3) + 1) as usize)
}
#[inline]
pub fn try_validate_bitfield_offset(
offset: i64,
bit_count: u8,
multiply_offset: bool,
) -> Option<(i64, i64)> {
if bit_count == 0 {
return None;
}
let normalized_offset = if multiply_offset {
offset.checked_mul(bit_count as i64)?
} else {
offset
};
if normalized_offset < 0 {
return None;
}
let end_offset = normalized_offset.checked_add(bit_count as i64 - 1)?;
if Self::is_valid_bit_offset(end_offset) {
Some((normalized_offset, end_offset))
} else {
None
}
}
#[inline]
pub fn try_validate_bit_pos_offsets(
start_offset: i64,
end_offset: i64,
offset_type: u8,
has_start_offset: bool,
has_end_offset: bool,
) -> bool {
let max_offset = if offset_type == 0x1 {
MAX_OFFSET_FOR_BITMAP_LENGTH
} else {
MAX_BITMAP_PAYLOAD_BYTES as i64 - 1
};
if has_start_offset && !(start_offset >= -max_offset && start_offset <= max_offset) {
return true;
}
if has_end_offset && !(end_offset >= -max_offset && end_offset <= max_offset) {
return true;
}
false
}
#[inline]
pub fn normalize_bit_count_offsets(
start_offset: &mut i64,
end_offset: &mut i64,
offset_type: u8,
) {
let max_offset = if offset_type == 0x1 {
MAX_OFFSET_FOR_BITMAP_LENGTH
} else {
MAX_BITMAP_PAYLOAD_BYTES as i64 - 1
};
if *start_offset < -max_offset {
*start_offset = -max_offset;
} else if *start_offset > max_offset {
*start_offset = max_offset;
}
if *end_offset < -max_offset {
*end_offset = -max_offset;
} else if *end_offset > max_offset {
*end_offset = max_offset;
}
}
#[inline]
pub const fn length_in_bytes(offset: i64) -> Option<usize> {
Self::try_validate_length_in_bytes(offset)
}
#[inline]
pub fn is_large_enough(vlen: usize, offset: i64) -> bool {
match Self::length_in_bytes(offset) {
Some(len) => len <= vlen,
None => false,
}
}
#[inline]
pub fn new_block_alloc_length(value_len: usize, offset: i64) -> usize {
let length_in_bytes = Self::length_in_bytes(offset).unwrap_or(0);
value_len.max(length_in_bytes)
}
#[inline]
pub fn update_bitmap(value: &mut [u8], offset: i64, set: u8) -> u8 {
let byte_index = (offset >> 3) as usize;
let bit_index = 7 - (offset & 7) as u32;
let byte_val = value[byte_index];
let old_val = (byte_val >> bit_index) & 1;
if set == 1 {
value[byte_index] |= 1 << bit_index;
} else {
value[byte_index] &= !(1 << bit_index);
}
old_val
}
#[inline(always)]
pub const fn process_negative_offset(offset: i64, val_len: i64) -> i64 {
if val_len <= 0 {
0
} else {
(offset % val_len) + val_len
}
}
#[inline(always)]
pub const fn reverse(n: u8) -> u8 {
n.reverse_bits()
}
}