Push zpwxxpnpktps #67
@@ -27,14 +27,19 @@ impl ColumnarBitMatrix {
|
||||
Ok(Self { cols, n: meta.n })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn n(&self) -> usize { self.n }
|
||||
#[inline]
|
||||
pub(crate) fn n_cols(&self) -> usize { self.cols.len() }
|
||||
#[inline]
|
||||
pub(crate) fn col(&self, c: usize) -> &PersistentBitVec { &self.cols[c] }
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn row(&self, slot: usize) -> Box<[bool]> {
|
||||
self.cols.iter().map(|c| c.get(slot)).collect()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn fill_row(&self, slot: usize, buf: &mut [u32]) {
|
||||
for (c, col) in self.cols.iter().enumerate() {
|
||||
buf[c] = col.get(slot) as u32;
|
||||
|
||||
@@ -58,17 +58,20 @@ impl PackedBitMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn row(&self, slot: usize) -> Box<[bool]> {
|
||||
(0..self.n_cols).map(|c| {
|
||||
(self.mmap[self.data_offsets[c] + (slot >> 3)] >> (slot & 7)) & 1 != 0
|
||||
}).collect()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn col_bytes(&self, c: usize) -> &[u8] {
|
||||
let start = self.data_offsets[c];
|
||||
&self.mmap[start..start + self.n_rows.div_ceil(8)]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn col_words(&self, c: usize) -> &[u64] {
|
||||
let nw = self.n_rows.div_ceil(64);
|
||||
// SAFETY: data_offsets[c] is always 8-byte aligned.
|
||||
@@ -78,6 +81,7 @@ impl PackedBitMatrix {
|
||||
unsafe { std::slice::from_raw_parts(ptr, nw) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn col_slice(&self, c: usize) -> BitSliceView<'_> {
|
||||
BitSliceView::new(self.col_words(c), self.n_rows)
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ impl PersistentBitMatrix {
|
||||
Ok(Self::Implicit { n_rows: meta.n, n_cols: 1 })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn n(&self) -> usize {
|
||||
match self {
|
||||
Self::Columnar(m) => m.n(),
|
||||
@@ -63,6 +64,7 @@ impl PersistentBitMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn n_cols(&self) -> usize {
|
||||
match self {
|
||||
Self::Columnar(m) => m.n_cols(),
|
||||
@@ -71,6 +73,7 @@ impl PersistentBitMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn col(&self, c: usize) -> &PersistentBitVec {
|
||||
match self {
|
||||
Self::Columnar(m) => m.col(c),
|
||||
@@ -78,6 +81,7 @@ impl PersistentBitMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn col_view(&self, c: usize) -> BitSliceView<'_> {
|
||||
match self {
|
||||
Self::Columnar(m) => m.col(c).view(),
|
||||
@@ -91,6 +95,7 @@ impl PersistentBitMatrix {
|
||||
/// Unlike [`col_view`](Self::col_view), this never panics on `Implicit`
|
||||
/// (every column reads as present, per the mono-genome fast path) — safe
|
||||
/// to call for any `c < self.n_cols()`.
|
||||
#[inline]
|
||||
pub fn get(&self, c: usize, slot: usize) -> u32 {
|
||||
match self {
|
||||
Self::Columnar(m) => m.col(c).get(slot) as u32,
|
||||
@@ -109,6 +114,7 @@ impl PersistentBitMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn row(&self, slot: usize) -> Box<[bool]> {
|
||||
match self {
|
||||
Self::Columnar(m) => m.row(slot),
|
||||
@@ -118,6 +124,7 @@ impl PersistentBitMatrix {
|
||||
}
|
||||
|
||||
/// Fill `buf[i]` with `col_i[slot]` as 0/1 u32, without allocating.
|
||||
#[inline]
|
||||
pub fn fill_row(&self, slot: usize, buf: &mut [u32]) {
|
||||
match self {
|
||||
Self::Columnar(m) => m.fill_row(slot, buf),
|
||||
@@ -177,6 +184,7 @@ impl PersistentBitMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn count_ones(&self) -> Array1<u64> {
|
||||
match self {
|
||||
Self::Columnar(m) => m.count_ones(),
|
||||
@@ -219,13 +227,16 @@ impl PersistentBitMatrix {
|
||||
// ── Trait impls ───────────────────────────────────────────────────────────────
|
||||
|
||||
impl ColumnWeights for PersistentBitMatrix {
|
||||
#[inline]
|
||||
fn col_weights(&self) -> Array1<u64> { self.count_ones() }
|
||||
}
|
||||
|
||||
impl BitPartials for PersistentBitMatrix {
|
||||
#[inline]
|
||||
fn partial_jaccard(&self) -> (Array2<u64>, Array2<u64>) {
|
||||
self.partial_jaccard_dist_matrix()
|
||||
}
|
||||
#[inline]
|
||||
fn partial_hamming(&self) -> Array2<u64> {
|
||||
self.partial_hamming_dist_matrix()
|
||||
}
|
||||
|
||||
@@ -51,16 +51,20 @@ impl PersistentBitVec {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.n
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.n == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, slot: usize) -> bool {
|
||||
(self.mmap[HEADER_SIZE + (slot >> 3)] >> (slot & 7)) & 1 != 0
|
||||
}
|
||||
@@ -104,37 +108,46 @@ impl PersistentBitVec {
|
||||
}
|
||||
|
||||
// SAFETY: mmap is page-aligned, HEADER_SIZE=16 divisible by 8 → u64-aligned.
|
||||
#[inline]
|
||||
fn data_words(&self) -> &[u64] {
|
||||
let nw = n_words(self.n);
|
||||
let ptr = self.mmap[HEADER_SIZE..].as_ptr() as *const u64;
|
||||
unsafe { std::slice::from_raw_parts(ptr, nw) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn view(&self) -> BitSliceView<'_> {
|
||||
BitSliceView::new(self.data_words(), self.n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn words(&self) -> &[u64] {
|
||||
self.data_words()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn count_ones(&self) -> u64 {
|
||||
self.view().count_ones()
|
||||
}
|
||||
#[inline]
|
||||
pub fn count_zeros(&self) -> u64 {
|
||||
self.view().count_zeros()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn partial_jaccard_dist(&self, other: &PersistentBitVec) -> (u64, u64) {
|
||||
self.view().partial_jaccard_dist(other.view())
|
||||
}
|
||||
#[inline]
|
||||
pub fn jaccard_dist(&self, other: &PersistentBitVec) -> f64 {
|
||||
self.view().jaccard_dist(other.view())
|
||||
}
|
||||
#[inline]
|
||||
pub fn hamming_dist(&self, other: &PersistentBitVec) -> u64 {
|
||||
self.view().hamming_dist(other.view())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> BitIter<'_> {
|
||||
BitIter {
|
||||
words: self.data_words(),
|
||||
@@ -147,6 +160,7 @@ impl PersistentBitVec {
|
||||
impl<'a> IntoIterator for &'a PersistentBitVec {
|
||||
type Item = bool;
|
||||
type IntoIter = BitIter<'a>;
|
||||
#[inline]
|
||||
fn into_iter(self) -> BitIter<'a> {
|
||||
self.iter()
|
||||
}
|
||||
@@ -164,6 +178,7 @@ impl ExactSizeIterator for BitIter<'_> {}
|
||||
|
||||
impl Iterator for BitIter<'_> {
|
||||
type Item = bool;
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<bool> {
|
||||
if self.slot >= self.n {
|
||||
return None;
|
||||
@@ -172,6 +187,7 @@ impl Iterator for BitIter<'_> {
|
||||
self.slot += 1;
|
||||
Some(v)
|
||||
}
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let rem = self.n - self.slot;
|
||||
(rem, Some(rem))
|
||||
@@ -314,17 +330,21 @@ impl PersistentBitVecBuilder {
|
||||
Self::build_from_counts(source, 1, path)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.n
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.n == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, slot: usize) -> bool {
|
||||
(self.mmap[HEADER_SIZE + (slot >> 3)] >> (slot & 7)) & 1 != 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set(&mut self, slot: usize, value: bool) {
|
||||
let bit = 1u64 << (slot & 63);
|
||||
if value {
|
||||
@@ -334,6 +354,7 @@ impl PersistentBitVecBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn data_words(&self) -> &[u64] {
|
||||
let nw = n_words(self.n);
|
||||
let ptr = self.mmap[HEADER_SIZE..].as_ptr() as *const u64;
|
||||
@@ -341,16 +362,19 @@ impl PersistentBitVecBuilder {
|
||||
}
|
||||
|
||||
// SAFETY: same alignment argument as PersistentBitVec::data_words.
|
||||
#[inline]
|
||||
fn data_words_mut(&mut self) -> &mut [u64] {
|
||||
let nw = n_words(self.n);
|
||||
let ptr = self.mmap[HEADER_SIZE..].as_mut_ptr() as *mut u64;
|
||||
unsafe { std::slice::from_raw_parts_mut(ptr, nw) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn view(&self) -> BitSliceView<'_> {
|
||||
BitSliceView::new(self.data_words(), self.n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn words(&self) -> &[u64] {
|
||||
self.data_words()
|
||||
}
|
||||
@@ -472,6 +496,7 @@ impl PersistentBitVecBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> BitSliceIter<'_> {
|
||||
self.view().iter()
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ impl PersistentCompactIntVecBuilder {
|
||||
Ok(Self { path: path.to_path_buf(), mmap, n, overflow })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, slot: usize) -> u32 {
|
||||
match self.mmap[HEADER_SIZE + slot] {
|
||||
255 => *self.overflow.get(&slot).expect("sentinel without overflow entry"),
|
||||
@@ -59,6 +60,7 @@ impl PersistentCompactIntVecBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set(&mut self, slot: usize, value: u32) {
|
||||
if value < 255 {
|
||||
self.mmap[HEADER_SIZE + slot] = value as u8;
|
||||
@@ -69,20 +71,28 @@ impl PersistentCompactIntVecBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize { self.n }
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool { self.n == 0 }
|
||||
|
||||
#[inline]
|
||||
pub fn primary_bytes(&self) -> &[u8] { &self.mmap[HEADER_SIZE..HEADER_SIZE + self.n] }
|
||||
#[inline]
|
||||
pub fn primary_bytes_mut(&mut self) -> &mut [u8] { &mut self.mmap[HEADER_SIZE..HEADER_SIZE + self.n] }
|
||||
#[inline]
|
||||
pub fn clear_overflow(&mut self) { self.overflow.clear(); }
|
||||
|
||||
#[inline]
|
||||
pub fn sum(&self) -> u64 {
|
||||
byte_sum(&self.mmap[HEADER_SIZE..HEADER_SIZE + self.n], self.overflow.values().copied())
|
||||
}
|
||||
#[inline]
|
||||
pub fn count_nonzero(&self) -> u64 {
|
||||
byte_count_nonzero(&self.mmap[HEADER_SIZE..HEADER_SIZE + self.n])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn view(&self) -> IntSliceView<'_> {
|
||||
// Builder overflow is a HashMap, not sorted raw bytes — convert on the fly
|
||||
// by collecting into a sorted vec and storing in a thread-local buffer.
|
||||
@@ -94,10 +104,12 @@ impl PersistentCompactIntVecBuilder {
|
||||
IntSliceView::new(primary, &[], 0, self.n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn overflow_entries(&self) -> impl Iterator<Item = (usize, u32)> + '_ {
|
||||
self.overflow.iter().map(|(&k, &v)| (k, v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inc(&mut self, slot: usize) {
|
||||
let v = self.get(slot);
|
||||
self.set(slot, v.saturating_add(1));
|
||||
|
||||
@@ -36,14 +36,19 @@ impl ColumnarCompactIntMatrix {
|
||||
Ok(Self { cols, n: meta.n })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn n(&self) -> usize { self.n }
|
||||
#[inline]
|
||||
pub(crate) fn n_cols(&self) -> usize { self.cols.len() }
|
||||
#[inline]
|
||||
pub(crate) fn col(&self, c: usize) -> &PersistentCompactIntVec { &self.cols[c] }
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn row(&self, slot: usize) -> Box<[u32]> {
|
||||
self.cols.iter().map(|c| c.get(slot)).collect()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn fill_row(&self, slot: usize, buf: &mut [u32]) {
|
||||
for (c, col) in self.cols.iter().enumerate() { buf[c] = col.get(slot); }
|
||||
}
|
||||
@@ -142,6 +147,7 @@ impl PackedCompactIntMatrix {
|
||||
Ok(Self { mmap, n_rows, n_cols, columns })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn col_view(&self, c: usize) -> IntSliceView<'_> {
|
||||
let ci = &self.columns[c];
|
||||
let primary = &self.mmap[ci.primary_start..ci.primary_start + self.n_rows];
|
||||
@@ -158,10 +164,12 @@ impl PackedCompactIntMatrix {
|
||||
#[inline]
|
||||
pub(crate) fn get(&self, col: usize, slot: usize) -> u32 { self.col_view(col).get(slot) }
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn fill_row(&self, slot: usize, buf: &mut [u32]) {
|
||||
for c in 0..self.n_cols { buf[c] = self.get(c, slot); }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn row(&self, slot: usize) -> Box<[u32]> {
|
||||
(0..self.n_cols).map(|c| self.get(c, slot)).collect()
|
||||
}
|
||||
@@ -312,13 +320,16 @@ impl PersistentCompactIntMatrix {
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn n(&self) -> usize {
|
||||
match self { Self::Columnar(m) => m.n(), Self::Packed(m) => m.n_rows }
|
||||
}
|
||||
#[inline]
|
||||
pub fn n_cols(&self) -> usize {
|
||||
match self { Self::Columnar(m) => m.n_cols(), Self::Packed(m) => m.n_cols }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn col(&self, c: usize) -> &PersistentCompactIntVec {
|
||||
match self {
|
||||
Self::Columnar(m) => m.col(c),
|
||||
@@ -326,6 +337,7 @@ impl PersistentCompactIntMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn col_view(&self, c: usize) -> IntSliceView<'_> {
|
||||
match self {
|
||||
Self::Columnar(m) => m.col(c).view(),
|
||||
@@ -340,9 +352,11 @@ impl PersistentCompactIntMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn row(&self, slot: usize) -> Box<[u32]> {
|
||||
match self { Self::Columnar(m) => m.row(slot), Self::Packed(m) => m.row(slot) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn fill_row(&self, slot: usize, buf: &mut [u32]) {
|
||||
match self { Self::Columnar(m) => m.fill_row(slot, buf), Self::Packed(m) => m.fill_row(slot, buf) }
|
||||
}
|
||||
@@ -390,30 +404,39 @@ impl PersistentCompactIntMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sum(&self) -> Array1<u64> {
|
||||
match self { Self::Columnar(m) => m.sum(), Self::Packed(m) => m.sum() }
|
||||
}
|
||||
#[inline]
|
||||
pub fn count_nonzero(&self) -> Array1<u64> {
|
||||
match self { Self::Columnar(m) => m.count_nonzero(), Self::Packed(m) => m.count_nonzero() }
|
||||
}
|
||||
#[inline]
|
||||
pub fn partial_bray_dist_matrix(&self) -> Array2<u64> {
|
||||
match self { Self::Columnar(m) => m.partial_bray_dist_matrix(), Self::Packed(m) => m.partial_bray_dist_matrix() }
|
||||
}
|
||||
#[inline]
|
||||
pub fn partial_euclidean_dist_matrix(&self) -> Array2<f64> {
|
||||
match self { Self::Columnar(m) => m.partial_euclidean_dist_matrix(), Self::Packed(m) => m.partial_euclidean_dist_matrix() }
|
||||
}
|
||||
#[inline]
|
||||
pub fn partial_threshold_jaccard_dist_matrix(&self, threshold: u32) -> (Array2<u64>, Array2<u64>) {
|
||||
match self { Self::Columnar(m) => m.partial_threshold_jaccard_dist_matrix(threshold), Self::Packed(m) => m.partial_threshold_jaccard_dist_matrix(threshold) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn partial_relfreq_bray_dist_matrix(&self, col_sums: &Array1<u64>) -> Array2<f64> {
|
||||
match self { Self::Columnar(m) => m.partial_relfreq_bray_dist_matrix(col_sums), Self::Packed(m) => m.partial_relfreq_bray_dist_matrix(col_sums) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn partial_relfreq_euclidean_dist_matrix(&self, col_sums: &Array1<u64>) -> Array2<f64> {
|
||||
match self { Self::Columnar(m) => m.partial_relfreq_euclidean_dist_matrix(col_sums), Self::Packed(m) => m.partial_relfreq_euclidean_dist_matrix(col_sums) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn partial_hellinger_euclidean_dist_matrix(&self, col_sums: &Array1<u64>) -> Array2<f64> {
|
||||
match self { Self::Columnar(m) => m.partial_hellinger_euclidean_dist_matrix(col_sums), Self::Packed(m) => m.partial_hellinger_euclidean_dist_matrix(col_sums) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn append_column(dir: &Path, value_of: impl Fn(usize) -> u32) -> io::Result<()> {
|
||||
ColumnarCompactIntMatrix::append_column(dir, value_of)
|
||||
}
|
||||
@@ -424,16 +447,24 @@ impl PersistentCompactIntMatrix {
|
||||
use crate::traits::{ColumnWeights, CountPartials};
|
||||
|
||||
impl ColumnWeights for PersistentCompactIntMatrix {
|
||||
#[inline]
|
||||
fn col_weights(&self) -> Array1<u64> { self.sum() }
|
||||
#[inline]
|
||||
fn partial_kmer_counts(&self) -> Array1<u64> { self.count_nonzero() }
|
||||
}
|
||||
|
||||
impl CountPartials for PersistentCompactIntMatrix {
|
||||
#[inline]
|
||||
fn partial_bray(&self) -> Array2<u64> { self.partial_bray_dist_matrix() }
|
||||
#[inline]
|
||||
fn partial_euclidean(&self) -> Array2<f64> { self.partial_euclidean_dist_matrix() }
|
||||
#[inline]
|
||||
fn partial_threshold_jaccard(&self, t: u32) -> (Array2<u64>, Array2<u64>) { self.partial_threshold_jaccard_dist_matrix(t) }
|
||||
#[inline]
|
||||
fn partial_relfreq_bray(&self, g: &Array1<u64>) -> Array2<f64> { self.partial_relfreq_bray_dist_matrix(g) }
|
||||
#[inline]
|
||||
fn partial_relfreq_euclidean(&self, g: &Array1<u64>) -> Array2<f64> { self.partial_relfreq_euclidean_dist_matrix(g) }
|
||||
#[inline]
|
||||
fn partial_hellinger(&self, g: &Array1<u64>) -> Array2<f64> { self.partial_hellinger_euclidean_dist_matrix(g) }
|
||||
}
|
||||
|
||||
@@ -450,7 +481,9 @@ impl PersistentCompactIntMatrixBuilder {
|
||||
fs::create_dir_all(dir)?;
|
||||
Ok(Self { dir: dir.to_path_buf(), n, n_cols: 0 })
|
||||
}
|
||||
#[inline]
|
||||
pub fn n(&self) -> usize { self.n }
|
||||
#[inline]
|
||||
pub fn n_cols(&self) -> usize { self.n_cols }
|
||||
pub fn add_col(&mut self) -> io::Result<PersistentCompactIntVecBuilder> {
|
||||
let path = col_path(&self.dir, self.n_cols);
|
||||
|
||||
@@ -46,10 +46,14 @@ impl PersistentCompactIntVec {
|
||||
Ok(Self { mmap, n, n_overflow, step, index, primary_offset, data_offset, path: path.to_path_buf() })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn path(&self) -> &Path { &self.path }
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize { self.n }
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool { self.n == 0 }
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, slot: usize) -> u32 {
|
||||
match self.mmap[self.primary_offset + slot] {
|
||||
255 => self.overflow_get(slot),
|
||||
@@ -127,23 +131,27 @@ impl PersistentCompactIntVec {
|
||||
u32::from_le_bytes(self.mmap[off..off + 4].try_into().unwrap())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sum(&self) -> u64 {
|
||||
let primary = &self.mmap[self.primary_offset..self.primary_offset + self.n];
|
||||
byte_sum(primary, (0..self.n_overflow).map(|i| self.data_value(i)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn count_nonzero(&self) -> u64 {
|
||||
let primary = &self.mmap[self.primary_offset..self.primary_offset + self.n];
|
||||
byte_count_nonzero(primary)
|
||||
}
|
||||
|
||||
/// Lightweight zero-copy view — primary and overflow point into the mmap.
|
||||
#[inline]
|
||||
pub fn view(&self) -> IntSliceView<'_> {
|
||||
let primary = &self.mmap[self.primary_offset..self.primary_offset + self.n];
|
||||
let overflow_raw = &self.mmap[self.data_offset..self.data_offset + self.n_overflow * OVERFLOW_ENTRY_SIZE];
|
||||
IntSliceView::new(primary, overflow_raw, self.n_overflow, self.n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> Iter<'_> {
|
||||
Iter { pciv: self, slot: 0, overflow_pos: 0 }
|
||||
}
|
||||
@@ -256,6 +264,7 @@ impl PersistentCompactIntVec {
|
||||
impl<'a> IntoIterator for &'a PersistentCompactIntVec {
|
||||
type Item = u32;
|
||||
type IntoIter = Iter<'a>;
|
||||
#[inline]
|
||||
fn into_iter(self) -> Iter<'a> { self.iter() }
|
||||
}
|
||||
|
||||
@@ -270,6 +279,7 @@ impl ExactSizeIterator for Iter<'_> {}
|
||||
impl Iterator for Iter<'_> {
|
||||
type Item = u32;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<u32> {
|
||||
if self.slot >= self.pciv.n { return None; }
|
||||
let v = self.pciv.mmap[self.pciv.primary_offset + self.slot];
|
||||
@@ -283,6 +293,7 @@ impl Iterator for Iter<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let remaining = self.pciv.n - self.slot;
|
||||
(remaining, Some(remaining))
|
||||
|
||||
@@ -21,21 +21,27 @@ impl TempBitVec {
|
||||
PersistentBitVec::open(path)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.vec.len()
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.vec.is_empty()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get(&self, slot: usize) -> bool {
|
||||
self.vec.get(slot)
|
||||
}
|
||||
#[inline]
|
||||
pub fn count_ones(&self) -> u64 {
|
||||
self.vec.count_ones()
|
||||
}
|
||||
#[inline]
|
||||
pub fn view(&self) -> BitSliceView<'_> {
|
||||
self.vec.view()
|
||||
}
|
||||
#[inline]
|
||||
pub fn iter(&self) -> BitSliceIter<'_> {
|
||||
self.view().iter()
|
||||
}
|
||||
@@ -69,42 +75,52 @@ impl TempBitVecBuilder {
|
||||
Ok(TempBitVec { vec, _temp: temp })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set(&mut self, slot: usize, value: bool) {
|
||||
self.builder.set(slot, value);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn view(&self) -> BitSliceView<'_> {
|
||||
self.builder.view()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn or(&mut self, other: BitSliceView<'_>) {
|
||||
self.builder.or(other);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn and(&mut self, other: BitSliceView<'_>) {
|
||||
self.builder.and(other);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn xor(&mut self, other: BitSliceView<'_>) {
|
||||
self.builder.xor(other);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn not(&mut self) {
|
||||
self.builder.not();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn copy_from(&mut self, src: BitSliceView<'_>) {
|
||||
self.builder.copy_from(src);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn or_where(&mut self, col: IntSliceView<'_>, pred: impl Fn(u32) -> bool) {
|
||||
self.builder.or_where(col, pred);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn and_where(&mut self, col: IntSliceView<'_>, pred: impl Fn(u32) -> bool) {
|
||||
self.builder.and_where(col, pred);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn xor_where(&mut self, col: IntSliceView<'_>, pred: impl Fn(u32) -> bool) {
|
||||
self.builder.xor_where(col, pred);
|
||||
}
|
||||
|
||||
@@ -22,11 +22,17 @@ impl TempCompactIntVec {
|
||||
PersistentCompactIntVec::open(path)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize { self.vec.len() }
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool { self.vec.is_empty() }
|
||||
#[inline]
|
||||
pub fn get(&self, slot: usize) -> u32 { self.vec.get(slot) }
|
||||
#[inline]
|
||||
pub fn sum(&self) -> u64 { self.vec.sum() }
|
||||
#[inline]
|
||||
pub fn view(&self) -> IntSliceView<'_> { self.vec.view() }
|
||||
#[inline]
|
||||
pub fn iter(&self) -> crate::reader::Iter<'_> { self.vec.iter() }
|
||||
}
|
||||
|
||||
@@ -51,39 +57,53 @@ impl TempCompactIntVecBuilder {
|
||||
Ok(TempCompactIntVec { vec, _temp: temp })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn n(&self) -> usize { self.builder.len() }
|
||||
|
||||
#[inline]
|
||||
pub fn set(&mut self, slot: usize, value: u32) { self.builder.set(slot, value); }
|
||||
#[inline]
|
||||
pub fn get(&self, slot: usize) -> u32 { self.builder.get(slot) }
|
||||
|
||||
#[inline]
|
||||
pub fn primary_bytes(&self) -> &[u8] { self.builder.primary_bytes() }
|
||||
#[inline]
|
||||
pub fn primary_bytes_mut(&mut self) -> &mut [u8] { self.builder.primary_bytes_mut() }
|
||||
|
||||
#[inline]
|
||||
pub fn inc_present(&mut self, col: BitSliceView<'_>) {
|
||||
self.builder.inc_present(col);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inc_present_fast(&mut self, col: BitSliceView<'_>) {
|
||||
self.builder.inc_present_fast(col);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inc_predicate(&mut self, col: IntSliceView<'_>, pred: impl Fn(u32) -> bool) {
|
||||
self.builder.inc_predicate(col, pred);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inc_predicate_fast(&mut self, col: IntSliceView<'_>, pred: impl Fn(u32) -> bool) {
|
||||
self.builder.inc_predicate_fast(col, pred);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add(&mut self, other: IntSliceView<'_>) {
|
||||
self.builder.add(other);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mask_with(&mut self, mask: BitSliceView<'_>) {
|
||||
self.builder.mask_with(mask);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn min(&mut self, other: IntSliceView<'_>) { self.builder.min(other); }
|
||||
#[inline]
|
||||
pub fn max(&mut self, other: IntSliceView<'_>) { self.builder.max(other); }
|
||||
#[inline]
|
||||
pub fn diff(&mut self, other: IntSliceView<'_>) { self.builder.diff(other); }
|
||||
}
|
||||
|
||||
@@ -14,8 +14,11 @@ impl<'a> BitSliceView<'a> {
|
||||
#[inline]
|
||||
pub fn new(words: &'a [u64], n: usize) -> Self { Self { words, n } }
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize { self.n }
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool { self.n == 0 }
|
||||
#[inline]
|
||||
pub fn words(&self) -> &'a [u64] { self.words }
|
||||
|
||||
#[inline]
|
||||
@@ -60,6 +63,7 @@ impl<'a> BitSliceView<'a> {
|
||||
}
|
||||
pub fn count_zeros(&self) -> u64 { self.n as u64 - self.count_ones() }
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> BitSliceIter<'a> {
|
||||
BitSliceIter { words: self.words, slot: 0, n: self.n }
|
||||
}
|
||||
@@ -95,12 +99,14 @@ pub struct BitSliceIter<'a> {
|
||||
|
||||
impl Iterator for BitSliceIter<'_> {
|
||||
type Item = bool;
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<bool> {
|
||||
if self.slot >= self.n { return None; }
|
||||
let v = (self.words[self.slot >> 6] >> (self.slot & 63)) & 1 != 0;
|
||||
self.slot += 1;
|
||||
Some(v)
|
||||
}
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let rem = self.n - self.slot;
|
||||
(rem, Some(rem))
|
||||
@@ -126,11 +132,16 @@ impl<'a> IntSliceView<'a> {
|
||||
Self { primary, overflow_raw, n_overflow, n }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize { self.n }
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool { self.n == 0 }
|
||||
#[inline]
|
||||
pub fn primary_bytes(&self) -> &'a [u8] { self.primary }
|
||||
#[inline]
|
||||
pub fn n_overflow(&self) -> usize { self.n_overflow }
|
||||
|
||||
#[inline]
|
||||
pub fn overflow_entries(&self) -> impl Iterator<Item = (usize, u32)> + 'a {
|
||||
let raw = self.overflow_raw;
|
||||
let n_ov = self.n_overflow;
|
||||
@@ -190,6 +201,7 @@ impl<'a> IntSliceView<'a> {
|
||||
}
|
||||
|
||||
/// Sequential merge scan: yields all n values in slot order.
|
||||
#[inline]
|
||||
pub fn iter(&self) -> IntSliceViewIter<'a> {
|
||||
IntSliceViewIter {
|
||||
primary: self.primary,
|
||||
@@ -324,6 +336,7 @@ pub struct IntSliceViewIter<'a> {
|
||||
|
||||
impl Iterator for IntSliceViewIter<'_> {
|
||||
type Item = u32;
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<u32> {
|
||||
if self.slot >= self.n { return None; }
|
||||
let v = self.primary[self.slot];
|
||||
@@ -336,6 +349,7 @@ impl Iterator for IntSliceViewIter<'_> {
|
||||
Some(val)
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let rem = self.n - self.slot;
|
||||
(rem, Some(rem))
|
||||
|
||||
Reference in New Issue
Block a user