Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
rust: [stable, nightly]
rust: ["1.95", stable, nightly]
cargo_features: ['', 'alloc', 'default']

env:
Expand Down
3 changes: 2 additions & 1 deletion croaring/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "croaring"
version = "2.6.0"
edition = "2021"
edition = "2024"
authors = ["croaring-rs developers"]
license = "Apache-2.0"
description = "Rust wrapper for CRoaring"
Expand All @@ -10,6 +10,7 @@ readme = "../README.md"
keywords = ["RoaringBitmap", "croaring", "bitmap"]
categories = ["data-structures", "api-bindings", "no-std::no-alloc"]
documentation = "https://docs.rs/croaring"
rust-version = "1.95.0"

[features]
default = ["std", "allocator-api2"]
Expand Down
5 changes: 2 additions & 3 deletions croaring/benches/benches.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use criterion::{
black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput,
};
use criterion::{BatchSize, BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use std::hint::black_box;
use std::ops::ControlFlow;

use croaring::{Bitmap, Bitmap64, Portable};
Expand Down
5 changes: 3 additions & 2 deletions croaring/benches/performance_comparison.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use croaring::Bitmap;
use roaring::RoaringBitmap;
use std::hint::black_box;

use criterion::measurement::Measurement;
use criterion::{
black_box, criterion_group, criterion_main, BatchSize, BenchmarkGroup, BenchmarkId, Criterion,
BatchSize, BenchmarkGroup, BenchmarkId, Criterion, criterion_group, criterion_main,
};

fn compare<Prep1, Prep2, Bench1, Bench2, In1, In2, Out1, Out2, M>(
Expand Down Expand Up @@ -151,7 +152,7 @@ fn binops(c: &mut Criterion) {
};

macro_rules! comp_op {
($new1:ident, $inplace1:ident, $new2:expr, $inplace2:expr $(,)?) => {{
($new1:ident, $inplace1:ident, $new2:expr_2021, $inplace2:expr_2021 $(,)?) => {{
compare(
&mut c.benchmark_group(concat!(stringify!($new1), "_new")),
gen_ours,
Expand Down
32 changes: 15 additions & 17 deletions croaring/src/bitmap/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ impl Bitmap {
#[allow(clippy::assertions_on_constants)]
#[must_use]
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());
let result = Self { bitmap: *p };
// This depends somewhat heavily on the implementation of croaring,
// In particular, that `roaring_bitmap_t` doesn't store any pointers into itself
// (it can be moved safely), and can be freed with `free`, without freeing the underlying
// containers and auxiliary data. Ensure this is still valid every time we update
// the version of croaring.
const _: () = assert!(ffi::ROARING_VERSION_MAJOR == 4);
ffi::roaring_free(p.cast::<c_void>());
result
unsafe {
// Based heavily on the `roaring.hh` cpp header from croaring

assert!(!p.is_null());
let result = Self { bitmap: *p };
// This depends somewhat heavily on the implementation of croaring,
// In particular, that `roaring_bitmap_t` doesn't store any pointers into itself
// (it can be moved safely), and can be freed with `free`, without freeing the underlying
// containers and auxiliary data. Ensure this is still valid every time we update
// the version of croaring.
const _: () = assert!(ffi::ROARING_VERSION_MAJOR == 4);
ffi::roaring_free(p.cast::<c_void>());
result
}
}

/// Creates a new bitmap (initially empty)
Expand Down Expand Up @@ -1523,11 +1525,7 @@ impl Bitmap {
let mut element: u32 = 0;
let result = unsafe { ffi::roaring_bitmap_select(&self.bitmap, position, &mut element) };

if result {
Some(element)
} else {
None
}
if result { Some(element) } else { None }
}

/// Returns statistics about the composition of a roaring bitmap.
Expand Down
36 changes: 22 additions & 14 deletions croaring/src/bitmap/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,10 @@ impl Deserializer for Portable {

#[doc(alias = "roaring_bitmap_portable_deserialize")]
unsafe fn try_deserialize_unchecked(buffer: &[u8]) -> Bitmap {
let bitmap = ffi::roaring_bitmap_portable_deserialize(buffer.as_ptr().cast::<c_char>());
Bitmap::take_heap(bitmap)
unsafe {
let bitmap = ffi::roaring_bitmap_portable_deserialize(buffer.as_ptr().cast::<c_char>());
Bitmap::take_heap(bitmap)
}
}
}

Expand All @@ -175,13 +177,15 @@ impl ViewDeserializer for Portable {
///
#[doc(alias = "roaring_bitmap_portable_deserialize_frozen")]
unsafe fn deserialize_view(data: &[u8]) -> BitmapView<'_> {
// portable_deserialize_size does some amount of checks, and returns zero if data cannot be valid
debug_assert_ne!(
ffi::roaring_bitmap_portable_deserialize_size(data.as_ptr().cast(), data.len()),
0,
);
let roaring = ffi::roaring_bitmap_portable_deserialize_frozen(data.as_ptr().cast());
BitmapView::take_heap(roaring)
unsafe {
// portable_deserialize_size does some amount of checks, and returns zero if data cannot be valid
debug_assert_ne!(
ffi::roaring_bitmap_portable_deserialize_size(data.as_ptr().cast(), data.len()),
0,
);
let roaring = ffi::roaring_bitmap_portable_deserialize_frozen(data.as_ptr().cast());
BitmapView::take_heap(roaring)
}
}
}

Expand Down Expand Up @@ -226,8 +230,10 @@ impl Deserializer for Native {

#[doc(alias = "roaring_bitmap_deserialize")]
unsafe fn try_deserialize_unchecked(buffer: &[u8]) -> Bitmap {
let bitmap = ffi::roaring_bitmap_deserialize(buffer.as_ptr().cast::<c_void>());
Bitmap::take_heap(bitmap)
unsafe {
let bitmap = ffi::roaring_bitmap_deserialize(buffer.as_ptr().cast::<c_void>());
Bitmap::take_heap(bitmap)
}
}
}

Expand Down Expand Up @@ -261,9 +267,11 @@ impl ViewDeserializer for Frozen {
///
/// See [`BitmapView::deserialize`] for examples.
unsafe fn deserialize_view(data: &[u8]) -> BitmapView<'_> {
assert_eq!(data.as_ptr() as usize % Self::REQUIRED_ALIGNMENT, 0);
unsafe {
assert_eq!(data.as_ptr() as usize % Self::REQUIRED_ALIGNMENT, 0);

let roaring = ffi::roaring_bitmap_frozen_view(data.as_ptr().cast(), data.len());
BitmapView::take_heap(roaring)
let roaring = ffi::roaring_bitmap_frozen_view(data.as_ptr().cast(), data.len());
BitmapView::take_heap(roaring)
}
}
}
32 changes: 17 additions & 15 deletions croaring/src/bitmap/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,25 @@ impl<'a> BitmapView<'a> {
#[inline]
#[allow(clippy::assertions_on_constants)]
pub(crate) unsafe fn take_heap(p: *const roaring_bitmap_t) -> Self {
// This depends somewhat heavily on the implementation of croaring,
// In particular, that `roaring_bitmap_t` doesn't store any pointers into itself
// (it can be moved safely), and a "frozen" bitmap is stored in an arena, and the
// `containers` array is stored immediately after the roaring_bitmap_t data.
// Ensure this is still valid every time we update
// the version of croaring.
const _: () = assert!(ffi::ROARING_VERSION_MAJOR == 4);
unsafe {
// This depends somewhat heavily on the implementation of croaring,
// In particular, that `roaring_bitmap_t` doesn't store any pointers into itself
// (it can be moved safely), and a "frozen" bitmap is stored in an arena, and the
// `containers` array is stored immediately after the roaring_bitmap_t data.
// Ensure this is still valid every time we update
// the version of croaring.
const _: () = assert!(ffi::ROARING_VERSION_MAJOR == 4);

assert!(!p.is_null());
assert!(!p.is_null());

// We will use this in the Drop implementation to re-create this pointer to pass to roaring_bitmap_free
// If this fails, we would pass junk to roaring_bitmap_free in Drop.
assert_eq!(p, original_bitmap_ptr(&*p));
// We will use this in the Drop implementation to re-create this pointer to pass to roaring_bitmap_free
// If this fails, we would pass junk to roaring_bitmap_free in Drop.
assert_eq!(p, original_bitmap_ptr(&*p));

Self {
bitmap: *p,
phantom: PhantomData,
Self {
bitmap: *p,
phantom: PhantomData,
}
}
}

Expand All @@ -60,7 +62,7 @@ impl<'a> BitmapView<'a> {
/// The data must be the result of serializing a bitmap with the same serialization format
#[must_use]
pub unsafe fn deserialize<S: ViewDeserializer>(data: &'a [u8]) -> Self {
S::deserialize_view(data)
unsafe { S::deserialize_view(data) }
}

/// Create an owned, mutable bitmap from this view
Expand Down
2 changes: 1 addition & 1 deletion croaring/src/bitmap64/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl<'a> Bitmap64Cursor<'a> {
}

unsafe fn current_unchecked(&self) -> u64 {
ffi::roaring64_iterator_value(self.raw.as_ptr())
unsafe { ffi::roaring64_iterator_value(self.raw.as_ptr()) }
}

/// Moves the cursor to the next value in the bitmap
Expand Down
2 changes: 1 addition & 1 deletion croaring/src/bitmap64/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl Deserializer for Portable {
}

unsafe fn try_deserialize_unchecked(buffer: &[u8]) -> Bitmap64 {
Self::try_deserialize(buffer).unwrap_unchecked()
unsafe { Self::try_deserialize(buffer).unwrap_unchecked() }
}

fn find_end(buffer: &[u8]) -> Option<NonZeroUsize> {
Expand Down
16 changes: 9 additions & 7 deletions croaring/src/bitset/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ impl Bitset {
#[inline]
#[allow(clippy::assertions_on_constants)]
pub(super) unsafe fn take_heap(p: *mut ffi::bitset_t) -> Self {
assert!(!p.is_null());
let result = Self { bitset: p.read() };
// It seems unlikely that the bitset type will meaningfully change, but check if we ever go
// to a version 3.
const _: () = assert!(ffi::ROARING_VERSION_MAJOR == 4);
ffi::roaring_free(p.cast());
result
unsafe {
assert!(!p.is_null());
let result = Self { bitset: p.read() };
// It seems unlikely that the bitset type will meaningfully change, but check if we ever go
// to a version 3.
const _: () = assert!(ffi::ROARING_VERSION_MAJOR == 4);
ffi::roaring_free(p.cast());
result
}
}

/// Access the raw underlying slice
Expand Down
28 changes: 15 additions & 13 deletions croaring/src/callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,21 @@ impl<F, O> CallbackWrapper<F, O> {
F: FnMut(I) -> ControlFlow<O>,
I: panic::UnwindSafe,
{
let wrapper = &mut *(arg as *mut Self);
let f = &mut wrapper.f;
let f = AssertUnwindSafe(|| f(value));
let result = std::panic::catch_unwind(f);
match result {
Ok(ControlFlow::Continue(())) => true,
Ok(cf @ ControlFlow::Break(_)) => {
wrapper.result = Ok(cf);
false
}
Err(err) => {
wrapper.result = Err(err);
false
unsafe {
let wrapper = &mut *(arg as *mut Self);
let f = &mut wrapper.f;
let f = AssertUnwindSafe(|| f(value));
let result = std::panic::catch_unwind(f);
match result {
Ok(ControlFlow::Continue(())) => true,
Ok(cf @ ControlFlow::Break(_)) => {
wrapper.result = Ok(cf);
false
}
Err(err) => {
wrapper.result = Err(err);
false
}
}
}
}
Expand Down
Loading
Loading