Skip to main content

SeqVec

Struct SeqVec 

Source
pub struct SeqVec<T: Storable, E: Endianness, B: AsRef<[u64]> = Vec<u64>> { /* private fields */ }
Expand description

A compressed, indexed vector of integer sequences.

SeqVec stores multiple sequences of integers in a single compressed bitstream, with an auxiliary index for O(1) access to each sequence by its rank. This is ideal for representing collections of variable-length sequences with minimal memory overhead.

See the module-level documentation for detailed usage information.

§Type Parameters

  • T - The element type (e.g., u32, i16). Must implement Storable.
  • E - The Endianness of the underlying bitstream (LE or BE).
  • B - The backing buffer type, enabling owned (Vec<u64>) or borrowed (&[u64]) storage for zero-copy operations.

Implementations§

Source§

impl<T: Storable + 'static, E: Endianness> SeqVec<T, E, Vec<u64>>

Source

pub fn builder() -> SeqVecBuilder<T, E>

Creates a builder for constructing a SeqVec with custom settings.

This is the most flexible way to create a SeqVec, allowing customization of the compression codec and other parameters.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec, Codec};

let sequences: &[&[u32]] = &[&[1, 2, 3], &[10, 20]];

let vec: LESeqVec<u32> = SeqVec::builder()
    .codec(Codec::Zeta { k: Some(3) })
    .build(sequences)?;
Source

pub fn from_iter_builder<I, S>(iter: I) -> SeqVecFromIterBuilder<T, E, I>
where I: IntoIterator<Item = S>, S: AsRef<[T]>,

Creates a builder for constructing a SeqVec from an iterator.

This is useful for large datasets that are generated on the fly. The codec must be specified explicitly since single-pass construction cannot perform data analysis.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec, Codec};

// Generate sequences programmatically
let sequences = (0..50).map(|i| vec![i as u32; i % 5 + 1]);

let vec: LESeqVec<u32> = SeqVec::from_iter_builder(sequences)
    .codec(Codec::Gamma)
    .build()?;

assert_eq!(vec.num_sequences(), 50);
Source

pub unsafe fn from_raw_parts( data: Vec<u64>, bit_offsets: FixedVec<u64, u64, E, Vec<u64>>, encoding: Codes, ) -> Self

Creates a SeqVec from raw parts without validation.

§Arguments
  • data - The compressed data buffer containing encoded words.
  • bit_offsets - Bit offset index where each offset points to the start of a sequence. Must contain at least 2 elements: the start offset and end sentinel.
  • encoding - The codec specification used to encode the data.
§Safety

This method is unsafe because it does not validate that the data and bit_offsets are consistent with each other. The caller must ensure:

  • The bit_offsets array has at least 2 elements (start and end sentinel).
  • All offsets are valid bit positions within the data buffer.
  • The last offset equals the total number of bits in the compressed data.
Source

pub unsafe fn from_raw_parts_with_lengths( data: Vec<u64>, bit_offsets: FixedVec<u64, u64, E, Vec<u64>>, seq_lengths: Option<FixedVec<u64, u64, E, Vec<u64>>>, encoding: Codes, ) -> Self

Creates a SeqVec from raw parts with optional stored sequence lengths.

This method is identical to from_raw_parts but allows providing pre-computed per-sequence lengths for faster random access.

§Arguments
  • data - The compressed data buffer.
  • bit_offsets - Bit offset boundaries for each sequence.
  • seq_lengths - Optional per-sequence lengths. If provided, must have length equal to the number of sequences (offsets.len() - 1).
  • encoding - The codec specification used to encode the data.
§Safety

The caller must ensure that data, bit_offsets, and seq_lengths (if present) are consistent with each other and the codec.

Source§

impl<T, E, B> SeqVec<T, E, B>
where T: Storable + Send + Sync, E: Endianness + Send + Sync, B: AsRef<[u64]> + Send + Sync, for<'a> BufBitReader<E, MemWordReader<u64, &'a [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible> + Send,

Source

pub fn par_iter(&self) -> impl ParallelIterator<Item = Vec<T>> + '_

Returns a parallel iterator over all sequences, materializing each as Vec<T>.

This method uses Rayon to decompress and collect all sequences in parallel. Each sequence is fully decoded into a Vec<T> by its assigned thread before being yielded.

§Performance

Parallelization is beneficial when the dataset contains enough sequences and those sequences are sufficiently large to amortize thread overhead.

For consumptive operations (sum, count, fold) where the decoded data is not retained, prefer par_for_each which avoids allocation overhead.

For small datasets or very fast codecs, the sequential iter method may be faster due to better cache locality.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};
use rayon::prelude::*;

let sequences: &[&[u32]] = &[
    &[1, 2, 3],
    &[10, 20],
    &[100, 200, 300],
];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// Collect all sequences in parallel
let all_sequences: Vec<Vec<u32>> = vec.par_iter().collect();

assert_eq!(all_sequences.len(), 3);
assert_eq!(all_sequences[0], vec![1, 2, 3]);
Source

pub fn par_for_each<F, R>(&self, f: F) -> Vec<R>
where F: Fn(SeqIter<'_, T, E>) -> R + Sync + Send, R: Send,

Applies a function to each sequence in parallel without materialization.

Unlike par_iter, this method does not allocate a Vec<T> for each sequence. Instead, the closure receives a streaming SeqIter directly, enabling zero-allocation parallel processing.

§Performance

This method is optimal when:

  • The operation is purely consumptive (fold, sum, count, predicate check)
  • Memory allocation overhead is significant relative to decode time
  • Sequences are short enough that materialization cost matters

For operations that need to retain sequence data (collect, sort, store), use par_iter instead.

§Type Parameters
  • F: Closure type that processes a SeqIter and produces a result
  • R: Result type produced by the closure, must be Send
§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2, 3], &[10, 20], &[100]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// Sum each sequence without allocating intermediate Vecs
let sums: Vec<u64> = vec.par_for_each(|seq| seq.map(|v| v as u64).sum());
assert_eq!(sums, vec![6, 30, 100]);

// Count elements per sequence
let counts: Vec<usize> = vec.par_for_each(|seq| seq.count());
assert_eq!(counts, vec![3, 2, 1]);

// Check if any sequence contains a value > 50
let has_large: Vec<bool> = vec.par_for_each(|mut seq| seq.any(|v| v > 50));
assert_eq!(has_large, vec![false, false, true]);
§Comparison with par_iter
use compressed_intvec::seq::{SeqVec, LESeqVec};
use rayon::prelude::*;

let sequences: &[&[u32]] = &[&[1, 2, 3], &[10, 20]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// par_iter: allocates Vec<T> per sequence, then sums
let sums_alloc: Vec<u64> = vec
    .par_iter()
    .map(|s| s.iter().map(|&v| v as u64).sum())
    .collect();

// par_for_each: zero allocation, sums directly from iterator
let sums_noalloc: Vec<u64> = vec.par_for_each(|seq| seq.map(|v| v as u64).sum());

assert_eq!(sums_alloc, sums_noalloc);
Source

pub fn par_for_each_reduce<F, R, ID, OP>(&self, f: F, identity: ID, op: OP) -> R
where F: Fn(SeqIter<'_, T, E>) -> R + Sync + Send, R: Send, ID: Fn() -> R + Sync + Send, OP: Fn(R, R) -> R + Sync + Send,

Applies a function to each sequence in parallel and reduces results.

This is a convenience method combining par_for_each with a parallel reduction. Useful when the final result is a single aggregated value rather than a collection.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2, 3], &[10, 20], &[100]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// Total sum across all sequences
let total: u64 = vec.par_for_each_reduce(
    |seq| seq.map(|v| v as u64).sum::<u64>(),
    || 0u64,
    |a, b| a + b,
);
assert_eq!(total, 136); // 6 + 30 + 100

// Maximum element across all sequences
let max: u32 = vec.par_for_each_reduce(
    |seq| seq.max().unwrap_or(0),
    || 0u32,
    |a, b| a.max(b),
);
assert_eq!(max, 100);
Source

pub fn par_into_vecs(self) -> Vec<Vec<T>>

Consumes the SeqVec and decodes all sequences into separate vectors in parallel.

This method is a parallel version of into_vecs, leveraging Rayon to decompress multiple sequences concurrently. Each sequence is fully decompressed by its assigned thread.

§Performance

Parallelization is beneficial when:

  • The dataset is large enough to amortize thread overhead
  • Sequences are reasonably sized

For small datasets or very fast codecs, the sequential into_vecs method may be faster due to better cache locality.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[
    &[1, 2, 3],
    &[10, 20],
    &[100, 200, 300],
];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// Decode all sequences in parallel
let all_sequences: Vec<Vec<u32>> = vec.par_into_vecs();

assert_eq!(all_sequences.len(), 3);
assert_eq!(all_sequences[0], vec![1, 2, 3]);
assert_eq!(all_sequences[1], vec![10, 20]);
Source

pub fn par_decode_many( &self, indices: &[usize], ) -> Result<Vec<Vec<T>>, SeqVecError>

Retrieves multiple sequences in parallel.

This method uses Rayon to parallelize the retrieval of multiple sequences by index. It is particularly useful when accessing a large subset of sequences that are not contiguous.

§Errors

Returns SeqVecError::IndexOutOfBounds if any index is out of bounds.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[
    &[1, 2, 3],
    &[10, 20],
    &[100, 200, 300],
    &[1000],
];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

let indices = [3, 0, 2];
let sequences = vec.par_decode_many(&indices)?;
assert_eq!(sequences.len(), 3);
assert_eq!(sequences[0], vec![1000]);  // Index 3
assert_eq!(sequences[1], vec![1, 2, 3]); // Index 0
assert_eq!(sequences[2], vec![100, 200, 300]); // Index 2
Source

pub unsafe fn par_decode_many_unchecked(&self, indices: &[usize]) -> Vec<Vec<T>>

Retrieves multiple sequences in parallel without bounds checking.

§Safety

Calling this method with any out-of-bounds index in the indices slice is undefined behavior. In debug builds, assertions will panic.

Source

pub fn par_for_each_many<F, R>( &self, indices: &[usize], f: F, ) -> Result<Vec<R>, SeqVecError>
where F: Fn(SeqIter<'_, T, E>) -> R + Sync + Send, R: Send,

Applies a function to selected sequences in parallel without materialization.

This is the sparse-access equivalent of par_for_each, allowing zero-allocation processing of a subset of sequences by index.

§Errors

Returns SeqVecError::IndexOutOfBounds if any index is out of bounds.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2, 3], &[10, 20], &[100], &[1000, 2000]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// Sum only sequences at indices 0 and 2
let sums = vec.par_for_each_many(&[0, 2], |seq| seq.map(|v| v as u64).sum::<u64>())?;
assert_eq!(sums, vec![6, 100]);
Source§

impl<T: Storable + 'static, E: Endianness> SeqVec<T, E, Vec<u64>>

Source

pub fn from_slices<S: AsRef<[T]>>(sequences: &[S]) -> Result<Self, SeqVecError>

Creates a SeqVec from a slice of slices using default settings.

This method uses Codec::Auto to select an optimal codec based on the data distribution.

§Errors

Returns a SeqVecError if codec resolution or encoding fails.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2, 3], &[10, 20], &[100]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

assert_eq!(vec.num_sequences(), 3);
Source

pub fn into_vecs(self) -> Vec<Vec<T>>
where for<'a> BufBitReader<E, MemWordReader<u64, &'a [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible>,

Consumes the SeqVec and returns all sequences as a Vec<Vec<T>>.

This method decodes the entire compressed data, allocating a separate vector for each sequence. The operation requires time proportional to the total number of elements across all sequences.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2], &[10, 20, 30]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

let decoded: Vec<Vec<u32>> = vec.into_vecs();
assert_eq!(decoded, vec![vec![1, 2], vec![10, 20, 30]]);
Source§

impl<T: Storable, E: Endianness, B: AsRef<[u64]>> SeqVec<T, E, B>

Source

pub fn from_parts( data: B, bit_offsets_data: B, bit_offsets_len: usize, bit_offsets_num_bits: usize, encoding: Codes, ) -> Result<Self, SeqVecError>

Creates a SeqVec from raw components for zero-copy views.

This constructor is intended for advanced use cases such as memory-mapping a pre-built SeqVec from disk or creating a borrowed view.

§Arguments
  • data - The compressed bitstream buffer.
  • bit_offsets_data - The buffer containing the bit offsets index.
  • bit_offsets_len - Number of entries in the bit offsets index (N+1).
  • bit_offsets_num_bits - Bit width of each entry in the offsets index.
  • encoding - The codec used for compression.
§Errors

Returns SeqVecError::InvalidParameters if:

  • bit_offsets_len is zero (must have at least the sentinel entry).
  • The underlying FixedVec construction fails.
§Safety Considerations

The caller must ensure that:

  • data contains valid compressed data encoded with encoding. Invalid data will cause panics or incorrect results during decoding.
  • bit_offsets_data contains monotonically increasing bit positions. Unsorted offsets will cause out-of-order or corrupted sequence retrieval.
  • The sentinel value (final bit offset) does not exceed the total bits in data. Violations cause panics during decoding.
  • All bit positions fall within valid boundaries of the bitstream.
§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};
use compressed_intvec::fixed::FixedVec;
use dsi_bitstream::prelude::LE;
use dsi_bitstream::impls::{BufBitWriter, MemWordWriterVec};
use dsi_bitstream::prelude::{BitWrite, CodesWrite};

// Create a simple vector using high-level API
let sequences: &[&[u32]] = &[&[1, 2], &[3, 4, 5]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// In a real zero-copy scenario, these would come from disk/memory-map
let data = vec.as_limbs().to_vec();
let offsets_ref = vec.bit_offsets_ref();

// Verify structure is sound before reconstruction
assert_eq!(vec.num_sequences(), 2);
Source

pub fn from_parts_with_lengths( data: B, bit_offsets_data: B, bit_offsets_len: usize, bit_offsets_num_bits: usize, seq_lengths: Option<FixedVec<u64, u64, E, Vec<u64>>>, encoding: Codes, ) -> Result<Self, SeqVecError>

Creates a SeqVec from raw components with optional stored lengths.

Use this variant when you have pre-computed sequence lengths from an earlier encoding. The seq_lengths parameter must be consistent with bit_offsets when provided (element count must equal num_sequences()).

§Errors

Returns SeqVecError::InvalidParameters if the number of lengths does not equal the number of sequences.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

// Typical usage: start with high-level API
let sequences: &[&[u32]] = &[&[1, 2], &[3, 4, 5]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// Verify structure
assert!(!vec.has_stored_lengths());
assert_eq!(vec.num_sequences(), 2);
Source

pub unsafe fn from_parts_unchecked( data: B, bit_offsets: FixedVec<u64, u64, E, B>, encoding: Codes, ) -> Self

Creates a SeqVec from pre-built components without validation.

§Safety

The caller must ensure all components are consistent and valid. Mismatched parameters will lead to panics or incorrect data retrieval.

Source

pub unsafe fn from_parts_with_lengths_unchecked( data: B, bit_offsets: FixedVec<u64, u64, E, B>, seq_lengths: Option<FixedVec<u64, u64, E, Vec<u64>>>, encoding: Codes, ) -> Self

Creates a SeqVec from pre-built components with optional lengths without validation.

§Safety

The caller must ensure all components are consistent and valid.

Source§

impl<T: Storable, E: Endianness, B: AsRef<[u64]>> SeqVec<T, E, B>

Source

pub fn num_sequences(&self) -> usize

Returns the number of sequences stored.

This is O(1) as it is derived from the bit offsets index length.

Source

pub fn is_empty(&self) -> bool

Returns true if there are no sequences stored.

Source

pub fn encoding(&self) -> Codes

Returns the compression codec used for encoding.

Source

pub fn as_limbs(&self) -> &[u64]

Returns a reference to the underlying compressed data buffer.

Source

pub fn bit_offsets_ref(&self) -> &FixedVec<u64, u64, E, B>

Returns a reference to the bit offsets index.

Source

pub fn has_stored_lengths(&self) -> bool

Returns true if explicit sequence lengths were stored at construction time.

Source

pub fn sequence_len(&self, index: usize) -> Option<usize>

Returns the length of sequence index if explicit lengths are stored.

Returns None if index is out of bounds or if lengths were not stored at construction time. Use has_stored_lengths to distinguish between these cases.

If lengths are stored, this query completes in O(1) time. Otherwise, determining sequence length requires full iteration. Store lengths at construction time via SeqVecBuilder::store_lengths when O(1) length queries are needed.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2, 3], &[10, 20]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// Without storing lengths, returns None
assert_eq!(vec.sequence_len(0), None);
assert!(!vec.has_stored_lengths());
Source

pub fn total_bits(&self) -> u64

Returns the total number of bits in the compressed data.

This is the sentinel value at the end of the bit offsets index.

Source

pub fn sequence_start_bit(&self, index: usize) -> Option<u64>

Returns the bit offset where sequence index starts in the compressed data.

Returns None if index >= num_sequences(). This is useful for understanding the compression footprint or verifying sequence boundaries.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2], &[3, 4, 5]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// First sequence always starts at bit 0
assert_eq!(vec.sequence_start_bit(0), Some(0));
// Second sequence starts after the first
assert!(vec.sequence_start_bit(1).is_some());
// Out of bounds
assert_eq!(vec.sequence_start_bit(2), None);
Source

pub unsafe fn sequence_start_bit_unchecked(&self, index: usize) -> u64

Returns the bit offset where sequence index starts, without bounds checking.

§Safety

The caller must ensure index < num_sequences().

Source

pub unsafe fn sequence_end_bit_unchecked(&self, index: usize) -> u64

Returns the bit offset immediately after sequence index ends.

This is equivalent to the start bit of the next sequence, or the total bit length for the final sequence. Useful for calculating per-sequence compression footprint.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2], &[3, 4, 5]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

let start = vec.sequence_start_bit(0).unwrap();
let end = unsafe { vec.sequence_end_bit_unchecked(0) };
println!("Sequence 0 occupies {} bits", end - start);
§Safety

The caller must ensure index < num_sequences().

Source§

impl<T: Storable, E: Endianness, B: AsRef<[u64]>> SeqVec<T, E, B>
where for<'a> BufBitReader<E, MemWordReader<u64, &'a [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible>,

Source

pub fn get(&self, index: usize) -> Option<SeqIter<'_, T, E>>

Returns an iterator over the elements of sequence index.

Returns None if index >= num_sequences().

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2, 3], &[4, 5]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

let first: Vec<u32> = vec.get(0).unwrap().collect();
assert_eq!(first, vec![1, 2, 3]);
Source

pub unsafe fn get_unchecked(&self, index: usize) -> SeqIter<'_, T, E>

Returns an iterator over the elements of sequence index without bounds checking.

§Safety

Calling this method with index >= num_sequences() is undefined behavior.

Source

pub fn decode_vec(&self, index: usize) -> Option<Vec<T>>

Returns the elements of sequence index as a newly allocated Vec.

Returns None if index >= num_sequences().

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[10, 20, 30]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

assert_eq!(vec.decode_vec(0), Some(vec![10, 20, 30]));
assert_eq!(vec.decode_vec(1), None);
Source

pub unsafe fn decode_vec_unchecked(&self, index: usize) -> Vec<T>

Returns the elements of sequence index as a newly allocated Vec without bounds checking.

§Safety

Calling this method with index >= num_sequences() is undefined behavior.

Source

pub fn decode_into(&self, index: usize, buf: &mut Vec<T>) -> Option<usize>

Decodes sequence index into the provided buffer.

The buffer is cleared before use. Returns the number of elements decoded, or None if index >= num_sequences().

This method is more efficient than decode_vec when reusing a buffer across multiple calls.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2], &[3, 4, 5]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

let mut buf = Vec::new();
assert_eq!(vec.decode_into(0, &mut buf), Some(2));
assert_eq!(buf, vec![1, 2]);

// Buffer is reused (cleared internally).
assert_eq!(vec.decode_into(1, &mut buf), Some(3));
assert_eq!(buf, vec![3, 4, 5]);
Source

pub unsafe fn decode_into_unchecked( &self, index: usize, buf: &mut Vec<T>, ) -> usize

Decodes sequence index into the provided buffer without bounds checking.

§Safety

Calling this method with index >= num_sequences() is undefined behavior.

Source

pub fn iter(&self) -> SeqVecIter<'_, T, E, B>

Returns an iterator over all sequences.

Each element of the returned iterator is a SeqIter for the corresponding sequence.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2], &[3], &[4, 5, 6]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

for (i, seq) in vec.iter().enumerate() {
    println!("Sequence {}: {:?}", i, seq.collect::<Vec<_>>());
}
Source

pub fn reader(&self) -> SeqVecReader<'_, T, E, B>

Creates a reusable reader for convenient random access to sequences.

The returned SeqVecReader provides a convenient interface for performing multiple sequence retrievals. While the current implementation is a thin wrapper, it serves as a natural extension point for future optimizations such as position tracking or caching.

§Performance Considerations
  • Zero-copy iteration: Returned iterators borrow directly from the compressed data without intermediate allocations.
  • Stateless operation: Each call to get is independent and creates a fresh SeqIter.
  • Convenience methods: The reader provides decode_vec and decode_into for common patterns.
§When to Use

Use a reader when:

  • You prefer a consistent interface for multiple accesses.
  • You want to use convenience methods like decode_vec or decode_into.
  • Future stateful optimizations would benefit your access pattern.

For single queries or simple iteration, direct calls to get or iter are equally efficient.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2], &[3, 4, 5], &[6]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

let mut reader = vec.reader();

// Perform multiple random accesses efficiently
assert_eq!(reader.decode_vec(2), Some(vec![6]));
assert_eq!(reader.decode_vec(0), Some(vec![1, 2]));
if let Some(seq) = reader.decode_vec(1) {
    for value in seq {
        assert!(value <= 5);
    }
}
Source

pub fn slice( &self, start: usize, len: usize, ) -> Option<SeqVecSlice<'_, T, E, B>>

Creates a zero-copy slice of a contiguous range of sequences.

The slice provides a view into len sequences starting at start, without copying the underlying compressed data.

§Arguments
  • start - The index of the first sequence in the slice.
  • len - The number of sequences to include in the slice.
§Returns

Returns Some(SeqVecSlice) if the range is valid, or None if start + len exceeds the number of sequences.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1, 2], &[3, 4, 5], &[6], &[7, 8]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

// Create a slice of sequences 1 and 2
let slice = vec.slice(1, 2).unwrap();
assert_eq!(slice.len(), 2);

// Index 0 of the slice refers to sequence 1 of the original vector
let seq: Vec<u32> = slice.get(0).unwrap().collect();
assert_eq!(seq, vec![3, 4, 5]);
Source

pub fn split_at(&self, mid: usize) -> Option<SeqVecSlicePair<'_, T, E, B>>

Splits the vector into two slices at the specified index.

Returns a tuple of two slices: the first contains sequences [0, mid) and the second contains sequences [mid, len).

§Returns

Returns Some((left_slice, right_slice)) if mid <= num_sequences(), or None if mid is out of bounds.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[&[1], &[2], &[3], &[4]];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

let (left, right) = vec.split_at(2).unwrap();
assert_eq!(left.len(), 2);
assert_eq!(right.len(), 2);

assert_eq!(left.decode_vec(0), Some(vec![1]));
assert_eq!(right.decode_vec(0), Some(vec![3]));
Source§

impl<T: Storable, E: Endianness, B: AsRef<[u64]>> SeqVec<T, E, B>
where for<'a> BufBitReader<E, MemWordReader<u64, &'a [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible>,

Source

pub fn decode_many(&self, indices: &[usize]) -> Result<Vec<Vec<T>>, SeqVecError>

Retrieves multiple sequences by their indices.

This method decodes the requested sequences in sorted order for efficient sequential access to the bitstream, then returns them in the order corresponding to the input indices.

§Arguments
  • indices - A slice of sequence indices to retrieve.
§Returns
  • Ok(Vec<Vec<T>>) containing the sequences in the order of indices.
  • Err(SeqVecError::IndexOutOfBounds(idx)) if any index is out of bounds.
§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[
    &[1, 2, 3],
    &[10, 20],
    &[100, 200, 300],
    &[1000],
];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

let indices = [3, 0, 2];
let sequences = vec.decode_many(&indices)?;
assert_eq!(sequences, vec![
    vec![1000],
    vec![1, 2, 3],
    vec![100, 200, 300],
]);
Source

pub unsafe fn decode_many_unchecked(&self, indices: &[usize]) -> Vec<Vec<T>>

Retrieves multiple sequences without bounds checking.

§Safety

Calling this method with any out-of-bounds index is undefined behavior.

Source

pub fn decode_many_into( &self, indices: &[usize], output: &mut Vec<Vec<T>>, ) -> Result<(), SeqVecError>

Decodes multiple sequences into a caller-provided output vector.

The output vector is cleared and resized to match indices.len(). Each sequence is decoded into its corresponding slot, maintaining the order specified by indices. This is more efficient than calling decode_vec repeatedly, as the decoding process traverses the compressed data in sorted order for better cache locality.

§Errors

Returns SeqVecError::IndexOutOfBounds if any index is out of bounds.

§Examples
use compressed_intvec::seq::{SeqVec, LESeqVec};

let sequences: &[&[u32]] = &[
    &[1, 2],
    &[10, 20],
    &[100, 200, 300],
];
let vec: LESeqVec<u32> = SeqVec::from_slices(sequences)?;

let indices = [2, 0, 1];
let mut output = Vec::new();
vec.decode_many_into(&indices, &mut output)?;

assert_eq!(output, vec![
    vec![100, 200, 300],
    vec![1, 2],
    vec![10, 20],
]);
Source

pub unsafe fn decode_many_into_unchecked( &self, indices: &[usize], output: &mut [Vec<T>], )

Decodes multiple sequences into a caller-provided output slice without bounds checking.

§Safety

Calling this method with any out-of-bounds index is undefined behavior.

Trait Implementations§

Source§

impl<T: Clone + Storable, E: Clone + Endianness, B: Clone + AsRef<[u64]>> Clone for SeqVec<T, E, B>

Source§

fn clone(&self) -> SeqVec<T, E, B>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug + Storable, E: Debug + Endianness, B: Debug + AsRef<[u64]>> Debug for SeqVec<T, E, B>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'a, T: Storable, E: Endianness, B: AsRef<[u64]>> IntoIterator for &'a SeqVec<T, E, B>
where for<'b> BufBitReader<E, MemWordReader<u64, &'b [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible>,

Source§

type Item = SeqIter<'a, T, E>

The type of the elements being iterated over.
Source§

type IntoIter = SeqVecIter<'a, T, E, B>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T: Storable + 'static, E: Endianness + 'static> IntoIterator for SeqVec<T, E, Vec<u64>>
where for<'a> BufBitReader<E, MemWordReader<u64, &'a [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible>,

Source§

type Item = SeqIter<'static, T, E>

The type of the elements being iterated over.
Source§

type IntoIter = SeqVecIntoIter<T, E>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T: Storable, E: Endianness, B: AsRef<[u64]> + MemDbgImpl + FlatType> MemDbgImpl for SeqVec<T, E, B>

Source§

fn _mem_dbg_rec_on( &self, writer: &mut impl Write, total_size: usize, max_depth: usize, prefix: &mut String, _is_last: bool, flags: DbgFlags, _dbg_refs: &mut HashSet<usize>, ) -> Result

Source§

fn _mem_dbg_depth_on( &self, writer: &mut impl Write, total_size: usize, max_depth: usize, prefix: &mut String, field_name: Option<&str>, is_last: bool, padded_size: usize, flags: DbgFlags, dbg_refs: &mut HashSet<usize>, ) -> Result<(), Error>

Source§

fn _mem_dbg_depth_on_impl( &self, writer: &mut impl Write, total_size: usize, max_depth: usize, prefix: &mut String, field_name: Option<&str>, is_last: bool, padded_size: usize, flags: DbgFlags, dbg_refs: &mut HashSet<usize>, ref_display: RefDisplay, ) -> Result<(), Error>

Internal implementation for depth display. Read more
Source§

impl<T: Storable, E: Endianness, B: AsRef<[u64]> + MemSize + FlatType> MemSize for SeqVec<T, E, B>

Source§

fn mem_size_rec( &self, flags: SizeFlags, _refs: &mut HashMap<usize, usize>, ) -> usize

Recursive implementation that tracks visited references for deduplication. Read more
Source§

fn mem_size(&self, flags: SizeFlags) -> usize

Returns the (recursively computed) overall memory size of the structure in bytes.
Source§

impl<'a, T, E, B> PartialEq<&SeqVec<T, E, B>> for SeqVecSlice<'a, T, E, B>
where T: Storable + PartialEq, E: Endianness, B: AsRef<[u64]>, for<'b> BufBitReader<E, MemWordReader<u64, &'b [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible>,

Source§

fn eq(&self, other: &&SeqVec<T, E, B>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<'a, T, E, B> PartialEq<SeqVec<T, E, B>> for SeqVecSlice<'a, T, E, B>
where T: Storable + PartialEq, E: Endianness, B: AsRef<[u64]>, for<'b> BufBitReader<E, MemWordReader<u64, &'b [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible>,

Source§

fn eq(&self, other: &SeqVec<T, E, B>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<'a, T, E, B> PartialEq<SeqVecSlice<'a, T, E, B>> for SeqVec<T, E, B>
where T: Storable + PartialEq, E: Endianness, B: AsRef<[u64]>, for<'b> BufBitReader<E, MemWordReader<u64, &'b [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible>,

Source§

fn eq(&self, other: &SeqVecSlice<'a, T, E, B>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: Storable + PartialEq, E: Endianness, B: AsRef<[u64]>> PartialEq for SeqVec<T, E, B>
where for<'a> BufBitReader<E, MemWordReader<u64, &'a [u64], true>, DefaultReadParams>: BitRead<E, Error = Infallible> + CodesRead<E> + BitSeek<Error = Infallible>,

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.

Auto Trait Implementations§

§

impl<T, E, B> Freeze for SeqVec<T, E, B>
where B: Freeze,

§

impl<T, E, B> RefUnwindSafe for SeqVec<T, E, B>

§

impl<T, E, B> Send for SeqVec<T, E, B>
where B: Send, T: Send,

§

impl<T, E, B> Sync for SeqVec<T, E, B>
where B: Sync, T: Sync,

§

impl<T, E, B> Unpin for SeqVec<T, E, B>
where B: Unpin, T: Unpin, E: Unpin,

§

impl<T, E, B> UnsafeUnpin for SeqVec<T, E, B>
where B: UnsafeUnpin,

§

impl<T, E, B> UnwindSafe for SeqVec<T, E, B>
where B: UnwindSafe, T: UnwindSafe, E: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CastableFrom<T> for T

Source§

fn cast_from(value: T) -> T

Call Self as W
Source§

impl<T, U> CastableInto<U> for T
where U: CastableFrom<T>,

Source§

fn cast(self) -> U

Call W::cast_from(self)
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DowncastableFrom<T> for T

Source§

fn downcast_from(value: T) -> T

Truncate the current UnsignedInt to a possibly smaller size
Source§

impl<T, U> DowncastableInto<U> for T
where U: DowncastableFrom<T>,

Source§

fn downcast(self) -> U

Call W::downcast_from(self)
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> MemDbg for T
where T: MemDbgImpl,

Source§

fn mem_dbg(&self, flags: DbgFlags) -> Result<(), Error>

Writes to stderr debug info about the structure memory usage, expanding all levels of nested structures.
Source§

fn mem_dbg_on( &self, writer: &mut impl Write, flags: DbgFlags, ) -> Result<(), Error>

Writes to a core::fmt::Write debug info about the structure memory usage, expanding all levels of nested structures.
Source§

fn mem_dbg_depth(&self, max_depth: usize, flags: DbgFlags) -> Result<(), Error>

Writes to stderr debug info about the structure memory usage as mem_dbg, but expanding only up to max_depth levels of nested structures.
Source§

fn mem_dbg_depth_on( &self, writer: &mut impl Write, max_depth: usize, flags: DbgFlags, ) -> Result<(), Error>

Writes to a core::fmt::Write debug info about the structure memory usage as mem_dbg_on, but expanding only up to max_depth levels of nested structures.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Splat<T> for T

Source§

fn splat(value: T) -> T

Source§

impl<T> To<T> for T

Source§

fn to(self) -> T

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> UpcastableFrom<T> for T

Source§

fn upcast_from(value: T) -> T

Extend the current UnsignedInt to a possibly bigger size.
Source§

impl<T, U> UpcastableInto<U> for T
where U: UpcastableFrom<T>,

Source§

fn upcast(self) -> U

Call W::upcast_from(self)