Skip to content

Commit

Permalink
Add serializers to Bitmap module
Browse files Browse the repository at this point in the history
  • Loading branch information
andreas committed Jun 12, 2023
1 parent 934e4b5 commit eaadd4a
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 57 deletions.
63 changes: 6 additions & 57 deletions croaring/src/bitmap/imp.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use ffi::roaring_bitmap_t;
use std::convert::TryInto;
use std::ffi::c_char;
use std::mem;
use std::ops::{Bound, RangeBounds};

Expand All @@ -9,7 +8,7 @@ use super::{Bitmap, Statistics};
impl Bitmap {
#[inline]
#[allow(clippy::assertions_on_constants)]
unsafe fn take_heap(p: *mut roaring_bitmap_t) -> Self {
pub(crate) unsafe fn take_heap(p: *mut roaring_bitmap_t) -> Self {
// Based heavily on the `roaring.hh` cpp header from croaring

assert!(!p.is_null());
Expand Down Expand Up @@ -737,14 +736,14 @@ impl Bitmap {
#[inline]
#[doc(alias = "roaring_bitmap_portable_size_in_bytes")]
pub fn get_serialized_size_in_bytes(&self) -> usize {
unsafe { ffi::roaring_bitmap_portable_size_in_bytes(&self.bitmap) }
super::PortableSerializer::get_serialized_size_in_bytes(&self)
}

/// Computes the serialized size in bytes of the Bitmap for the frozen format.
#[inline]
#[doc(alias = "roaring_bitmap_frozen_size_in_bytes")]
pub fn get_frozen_serialized_size_in_bytes(&self) -> usize {
unsafe { ffi::roaring_bitmap_frozen_size_in_bytes(&self.bitmap) }
super::FrozenSerializer::get_serialized_size_in_bytes(&self)
}

/// Serializes a bitmap to a slice of bytes.
Expand Down Expand Up @@ -793,20 +792,7 @@ impl Bitmap {
#[inline]
#[doc(alias = "roaring_bitmap_portable_serialize")]
pub fn serialize_into<'a>(&self, dst: &'a mut Vec<u8>) -> &'a [u8] {
let len = self.get_serialized_size_in_bytes();

dst.reserve(len);
let total_len = dst.len().checked_add(len).unwrap();

unsafe {
ffi::roaring_bitmap_portable_serialize(
&self.bitmap,
dst.spare_capacity_mut().as_mut_ptr().cast::<c_char>(),
);
dst.set_len(total_len);
}

dst
super::PortableSerializer::serialize_into(self, dst)
}

/// Serialize into the "frozen" format
Expand All @@ -815,33 +801,7 @@ impl Bitmap {
/// This means the returned slice may not start exactly at the beginning of the passed Vec
#[doc(alias = "roaring_bitmap_frozen_serialize")]
pub fn serialize_frozen_into<'a>(&self, dst: &'a mut Vec<u8>) -> &'a [u8] {
const REQUIRED_ALIGNMENT: usize = 32;
let len = self.get_frozen_serialized_size_in_bytes();

let offset = dst.len();
// Need to be able to add up to 31 extra bytes to align to 32 bytes
dst.reserve(len.checked_add(REQUIRED_ALIGNMENT - 1).unwrap());

let extra_offset = match (dst.as_ptr() as usize) % REQUIRED_ALIGNMENT {
0 => 0,
r => REQUIRED_ALIGNMENT - r,
};
let offset = offset.checked_add(extra_offset).unwrap();
let total_len = offset.checked_add(len).unwrap();
debug_assert!(dst.capacity() >= total_len);

// we must initialize up to offset
dst.resize(offset, 0);

unsafe {
ffi::roaring_bitmap_frozen_serialize(
&self.bitmap,
dst.as_mut_ptr().add(offset).cast::<c_char>(),
);
dst.set_len(total_len);
}

&dst[offset..total_len]
super::FrozenSerializer::serialize_into(self, dst)
}

/// Given a serialized bitmap as slice of bytes returns a bitmap instance.
Expand All @@ -867,18 +827,7 @@ impl Bitmap {
#[inline]
#[doc(alias = "roaring_bitmap_portable_deserialize_safe")]
pub fn try_deserialize(buffer: &[u8]) -> Option<Self> {
unsafe {
let bitmap = ffi::roaring_bitmap_portable_deserialize_safe(
buffer.as_ptr() as *const c_char,
buffer.len(),
);

if !bitmap.is_null() {
Some(Self::take_heap(bitmap))
} else {
None
}
}
super::PortableSerializer::try_deserialize(buffer)
}

/// Given a serialized bitmap as slice of bytes returns a bitmap instance.
Expand Down
2 changes: 2 additions & 0 deletions croaring/src/bitmap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ mod imp;
mod iter;
mod lazy;
mod ops;
mod serialization;
mod view;

pub use self::iter::BitmapIterator;
pub use self::lazy::LazyBitmap;
pub use self::serialization::{FrozenSerializer, NativeSerializer, PortableSerializer};
121 changes: 121 additions & 0 deletions croaring/src/bitmap/serialization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use super::Bitmap;

use std::ffi::{c_char, c_void};

pub struct PortableSerializer {}

impl PortableSerializer {
pub fn serialize_into<'a>(bitmap: &Bitmap, dst: &'a mut Vec<u8>) -> &'a [u8] {
let len = Self::get_serialized_size_in_bytes(bitmap);

dst.reserve(len);
let total_len = dst.len().checked_add(len).unwrap();

unsafe {
ffi::roaring_bitmap_portable_serialize(
&bitmap.bitmap,
dst.spare_capacity_mut().as_mut_ptr().cast::<c_char>(),
);
dst.set_len(total_len);
}

dst
}

pub fn get_serialized_size_in_bytes(bitmap: &Bitmap) -> usize {
unsafe { ffi::roaring_bitmap_portable_size_in_bytes(&bitmap.bitmap) }
}

pub fn try_deserialize(buffer: &[u8]) -> Option<Bitmap> {
unsafe {
let bitmap = ffi::roaring_bitmap_portable_deserialize_safe(
buffer.as_ptr() as *const c_char,
buffer.len(),
);

if !bitmap.is_null() {
Some(Bitmap::take_heap(bitmap))
} else {
None
}
}
}
}

pub struct NativeSerializer {}

impl NativeSerializer {
pub fn serialize_into<'a>(bitmap: &Bitmap, dst: &'a mut Vec<u8>) -> &'a [u8] {
let len = Self::get_serialized_size_in_bytes(bitmap);

dst.reserve(len);
let total_len = dst.len().checked_add(len).unwrap();

unsafe {
ffi::roaring_bitmap_serialize(
&bitmap.bitmap,
dst.spare_capacity_mut().as_mut_ptr().cast::<c_char>(),
);
dst.set_len(total_len);
}

dst
}

pub fn get_serialized_size_in_bytes(bitmap: &Bitmap) -> usize {
unsafe { ffi::roaring_bitmap_size_in_bytes(&bitmap.bitmap) }
}

pub fn try_deserialize(buffer: &[u8]) -> Option<Bitmap> {
unsafe {
let bitmap = ffi::roaring_bitmap_deserialize_safe(
buffer.as_ptr() as *const c_void,
buffer.len(),
);

if !bitmap.is_null() {
Some(Bitmap::take_heap(bitmap))
} else {
None
}
}
}
}

pub struct FrozenSerializer {}

impl FrozenSerializer {
pub fn serialize_into<'a>(bitmap: &Bitmap, dst: &'a mut Vec<u8>) -> &'a [u8] {
const REQUIRED_ALIGNMENT: usize = 32;
let len = Self::get_serialized_size_in_bytes(bitmap);

let offset = dst.len();
// Need to be able to add up to 31 extra bytes to align to 32 bytes
dst.reserve(len.checked_add(REQUIRED_ALIGNMENT - 1).unwrap());

let extra_offset = match (dst.as_ptr() as usize) % REQUIRED_ALIGNMENT {
0 => 0,
r => REQUIRED_ALIGNMENT - r,
};
let offset = offset.checked_add(extra_offset).unwrap();
let total_len = offset.checked_add(len).unwrap();
debug_assert!(dst.capacity() >= total_len);

// we must initialize up to offset
dst.resize(offset, 0);

unsafe {
ffi::roaring_bitmap_frozen_serialize(
&bitmap.bitmap,
dst.as_mut_ptr().add(offset).cast::<c_char>(),
);
dst.set_len(total_len);
}

&dst[offset..total_len]
}

pub fn get_serialized_size_in_bytes(bitmap: &Bitmap) -> usize {
unsafe { ffi::roaring_bitmap_frozen_size_in_bytes(&bitmap.bitmap) }
}
}

0 comments on commit eaadd4a

Please sign in to comment.