Skip to content

Commit

Permalink
Impl RoaringBitmap::from_bitmap_bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
lemolatoon committed Aug 21, 2024
1 parent 9e743c4 commit b485e51
Showing 1 changed file with 74 additions and 0 deletions.
74 changes: 74 additions & 0 deletions roaring/src/bitmap/inherent.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::cmp::Ordering;
use core::ops::RangeBounds;

use crate::bitmap::store::{BitmapStore, Store, BITMAP_LENGTH};
use crate::RoaringBitmap;

use super::container::Container;
Expand All @@ -22,6 +23,59 @@ impl RoaringBitmap {
RoaringBitmap { containers: Vec::new() }
}

/// Creates a `RoaringBitmap` from a byte slice.
///
/// # Panics
///
/// Panics if `offset` is not a multiple of 65536([u16::MAX] + 1).
///
/// # Examples
///
/// ```rust
/// use roaring::RoaringBitmap;
///
/// let bytes = [0b00000101, 0b00000010, 0b00000000, 0b10000000];
/// // ^^^^^^^^ ^^^^^^^^ ^^^^^^^^ ^^^^^^^^
/// // 76543210 98
/// let rb = RoaringBitmap::from_bytes(0, &bytes);
/// assert!(rb.contains(0));
/// assert!(!rb.contains(1));
/// assert!(rb.contains(2));
/// assert!(rb.contains(9));
/// assert!(rb.contains(31));
/// ```
pub fn from_bitmap_bytes(offset: u32, bytes: &[u8]) -> RoaringBitmap {
const BITS_IN_ONE_CONTAINER: usize = 8 * size_of::<u64>() * BITMAP_LENGTH;
const BYTE_IN_ONE_CONTAINER: usize = BITS_IN_ONE_CONTAINER / 8;
assert_eq!(offset % BITS_IN_ONE_CONTAINER as u32, 0);
let mut containers = Vec::with_capacity(bytes.len() / BYTE_IN_ONE_CONTAINER);
let bitmap_store_chunks = bytes.chunks(BYTE_IN_ONE_CONTAINER);

let (offset_key, _) = util::split(offset);
for (i, chunk) in bitmap_store_chunks.enumerate() {
let len: u64 = chunk.iter().map(|&b| b.count_ones() as u64).sum();
let mut bits: Box<[u64; BITMAP_LENGTH]> = Box::new([0; BITMAP_LENGTH]);
let bits_ptr = bits.as_mut_ptr().cast::<u64>();

debug_assert!(chunk.len() <= BITMAP_LENGTH * size_of::<u64>());
// Safety:
// * `chunk` is a slice of `bytes` and is guaranteed to be smaller than `BITMAP_LENGTH` u64s
unsafe {
core::ptr::copy_nonoverlapping(chunk.as_ptr(), bits_ptr.cast::<u8>(), chunk.len())
};

let store = BitmapStore::from_unchecked(len, bits);

let mut container =
Container { key: offset_key + i as u16, store: Store::Bitmap(store) };
container.ensure_correct_store();

containers.push(container);
}

RoaringBitmap { containers }
}

/// Creates a full `RoaringBitmap`.
///
/// # Examples
Expand Down Expand Up @@ -709,6 +763,26 @@ mod tests {
}
}

#[test]
fn test_from_bitmap_bytes() {
const OFFSET_MULTIPLE: u32 = 65536;
let mut bytes = vec![0xff; OFFSET_MULTIPLE as usize];
bytes.extend(&[0b00000001, 0b00000010, 0b00000011, 0b00000100]);

let rb = RoaringBitmap::from_bitmap_bytes(OFFSET_MULTIPLE, &bytes);
for i in 0..(OFFSET_MULTIPLE as u32) {
assert!(!rb.contains(i));
}
for i in 0..(OFFSET_MULTIPLE as u32) {
let i = i + OFFSET_MULTIPLE as u32;
assert!(rb.contains(i));
}
for bit in [0, 9, 16, 17, 34] {
let i = OFFSET_MULTIPLE as u32 + bit;
assert!(rb.contains(i));
}
}

#[test]
fn test_insert_remove_range_same_container() {
let mut b = RoaringBitmap::new();
Expand Down

0 comments on commit b485e51

Please sign in to comment.