-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
replace RoaringTreemap by TwoLevelRoaringBitmap
Benchmark results on insert_range (only bench available for 64-bit): group roaring64 treemap ----- --------- ------- from_empty_1000 1.00 87.6±4.76ns 10.6 GElem/sec 1.65 144.2±1.28ns 6.5 GElem/sec from_empty_10000 1.00 166.8±9.32ns 55.8 GElem/sec 1.28 213.6±7.26ns 43.6 GElem/sec from_empty_8589934590 1.01 151.5±0.99ms 52.8 GElem/sec 1.00 149.7±1.00ms 53.5 GElem/sec pre_populated_1000 1.00 139.3±19.83ns 6.7 GElem/sec 1.30 180.8±20.70ns 5.2 GElem/sec pre_populated_10000 1.00 235.4±83.29ns 39.6 GElem/sec 1.26 295.9±106.25ns 31.5 GElem/sec pre_populated_8589934590 1.00 74.8±2.56ms 107.0 GElem/sec 1.01 75.3±1.82ms 106.3 GElem/sec
- Loading branch information
1 parent
c7bab3c
commit d8bb37b
Showing
43 changed files
with
1,275 additions
and
3,384 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
use crate::{ContainerKey, RoaringBitmap, Value, ValueRange}; | ||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; | ||
use std::{ | ||
io, | ||
ops::{Bound, RangeBounds, RangeInclusive}, | ||
}; | ||
|
||
/// A compressed bitmap for 64-bit values. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```rust | ||
/// use roaring::Roaring64; | ||
/// | ||
/// let mut rb = Roaring64::new(); | ||
/// | ||
/// // insert all primes less than 10 | ||
/// rb.insert(2); | ||
/// rb.insert(3); | ||
/// rb.insert(5); | ||
/// rb.insert(7); | ||
/// println!("total bits set to true: {}", rb.len()); | ||
/// ``` | ||
pub type Roaring64 = RoaringBitmap<u64>; | ||
|
||
impl Value for u64 { | ||
type Key = u64; | ||
type Range = RangeInclusive<Self>; | ||
|
||
fn split(self) -> (Self::Key, u16) { | ||
(self >> 16, self as u16) | ||
} | ||
|
||
fn join(key: Self::Key, index: u16) -> Self { | ||
(key << 16) + u64::from(index) | ||
} | ||
|
||
fn range(range: impl RangeBounds<Self>) -> Option<Self::Range> { | ||
let start: u64 = match range.start_bound() { | ||
Bound::Included(&i) => i, | ||
Bound::Excluded(&i) => i.checked_add(1)?, | ||
Bound::Unbounded => 0, | ||
}; | ||
let end: u64 = match range.end_bound() { | ||
Bound::Included(&i) => i, | ||
Bound::Excluded(&i) => i.checked_sub(1)?, | ||
Bound::Unbounded => u64::MAX, | ||
}; | ||
|
||
if end < start { | ||
return None; | ||
} | ||
|
||
Some(start..=end) | ||
} | ||
|
||
fn max_containers() -> usize { | ||
// Theoretically, u64::MAX + 1. | ||
// Realistically we're probably capped at usize anyway. | ||
usize::MAX | ||
} | ||
} | ||
|
||
impl ContainerKey for u64 { | ||
#[inline(always)] | ||
fn size() -> usize { | ||
// Key is coded on 48-bit, the 16 upper ones are unused. | ||
6 | ||
} | ||
|
||
fn write(self, writer: &mut impl WriteBytesExt) -> io::Result<()> { | ||
writer.write_u48::<LittleEndian>(self) | ||
} | ||
|
||
fn read(reader: &mut impl ReadBytesExt) -> io::Result<Self> { | ||
reader.read_u48::<LittleEndian>() | ||
} | ||
} | ||
|
||
impl ValueRange<u64> for RangeInclusive<u64> { | ||
type KeyIterator = RangeInclusive<u64>; | ||
|
||
fn start(&self) -> (<u64 as Value>::Key, u16) { | ||
self.start().split() | ||
} | ||
|
||
fn end(&self) -> (<u64 as Value>::Key, u16) { | ||
self.end().split() | ||
} | ||
|
||
fn containers_count(&self) -> usize { | ||
let start = ValueRange::start(self).0; | ||
let end = ValueRange::end(self).0; | ||
(end - start) as usize + 1 | ||
} | ||
|
||
fn keys(self) -> Self::KeyIterator { | ||
let start = ValueRange::start(&self).0; | ||
let end = ValueRange::end(&self).0; | ||
start..=end | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
#[test] | ||
fn split() { | ||
assert_eq!((0x0000_0000_0000u64, 0x0000u16), 0x0000_0000_0000_0000u64.split()); | ||
assert_eq!((0x0000_0000_0000u64, 0x0001u16), 0x0000_0000_0000_0001u64.split()); | ||
assert_eq!((0x0000_0000_FFFFu64, 0xFFFEu16), 0x0000_0000_FFFF_FFFEu64.split()); | ||
assert_eq!((0x0000_0000_FFFFu64, 0xFFFFu16), 0x0000_0000_FFFF_FFFFu64.split()); | ||
assert_eq!((0x0000_0001_0000u64, 0x0000u16), 0x0000_0001_0000_0000u64.split()); | ||
assert_eq!((0x0000_0001_0000u64, 0x0001u16), 0x0000_0001_0000_0001u64.split()); | ||
assert_eq!((0xFFFF_FFFF_FFFFu64, 0xFFFEu16), 0xFFFF_FFFF_FFFF_FFFEu64.split()); | ||
assert_eq!((0xFFFF_FFFF_FFFFu64, 0xFFFFu16), 0xFFFF_FFFF_FFFF_FFFFu64.split()); | ||
} | ||
|
||
#[test] | ||
fn join() { | ||
assert_eq!(0x0000_0000_0000_0000u64, u64::join(0x0000_0000_0000u64, 0x0000u16)); | ||
assert_eq!(0x0000_0000_0000_0001u64, u64::join(0x0000_0000_0000u64, 0x0001u16)); | ||
assert_eq!(0x0000_0000_FFFF_FFFEu64, u64::join(0x0000_0000_FFFFu64, 0xFFFEu16)); | ||
assert_eq!(0x0000_0000_FFFF_FFFFu64, u64::join(0x0000_0000_FFFFu64, 0xFFFFu16)); | ||
assert_eq!(0x0000_0001_0000_0000u64, u64::join(0x0000_0001_0000u64, 0x0000u16)); | ||
assert_eq!(0x0000_0001_0000_0001u64, u64::join(0x0000_0001_0000u64, 0x0001u16)); | ||
assert_eq!(0xFFFF_FFFF_FFFF_FFFEu64, u64::join(0xFFFF_FFFF_FFFFu64, 0xFFFEu16)); | ||
assert_eq!(0xFFFF_FFFF_FFFF_FFFFu64, u64::join(0xFFFF_FFFF_FFFFu64, 0xFFFFu16)); | ||
} | ||
|
||
#[test] | ||
fn range() { | ||
assert_eq!(Some(1..=5), u64::range(1..6)); | ||
assert_eq!(Some(1..=u64::MAX), u64::range(1..)); | ||
assert_eq!(Some(0..=u64::MAX), u64::range(..)); | ||
assert_eq!(None, u64::range(5..5)); | ||
assert_eq!(Some(16..=16), u64::range(16..=16)) | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.