Skip to content

Commit 032253d

Browse files
committed
added convenience functions to unpack packed integers
1 parent d4f5fb2 commit 032253d

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

src/bit_vec/mod.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,57 @@ impl BitVec {
958958
}
959959
}
960960

961+
/// Extract a packed element from a bit vector. The element is encoded in the bits at the given
962+
/// `index`. The number of bits per encoded element is given by `n`.
963+
///
964+
/// This is a convenience method to access elements previously packed using the [`pack_sequence_*`] methods,
965+
/// and is equivalent to calling [`get_bits(index * n, n)`].
966+
/// It is thus safe to use this method with any index and any size n <= 64.
967+
///
968+
/// If the element is out of bounds, None is returned.
969+
/// The element is returned as a u64 value.
970+
///
971+
/// # Example
972+
/// ```rust
973+
/// use vers_vecs::BitVec;
974+
///
975+
/// let sequence = [10, 100, 124, 45, 223];
976+
/// let bv = BitVec::pack_sequence_u64(&sequence, 8);
977+
///
978+
/// assert_eq!(bv.unpack_element(0, 8), Some(10));
979+
/// assert_eq!(bv.unpack_element(2, 8), Some(124));
980+
/// ```
981+
///
982+
/// [`pack_sequence_*`]: BitVec::pack_sequence_u64
983+
/// [`get_bits(index * n, n)`]: BitVec::get_bits
984+
#[must_use]
985+
#[allow(clippy::inline_always)]
986+
#[inline(always)] // to gain optimization if n is constant
987+
pub fn unpack_element(&self, index: usize, n: usize) -> Option<u64> {
988+
self.get_bits(index * n, n)
989+
}
990+
991+
/// Extract a packed element from a bit vector. The element is encoded in the bits at the given
992+
/// `index`. The number of bits per encoded element is given by `n`.
993+
///
994+
/// This is a convenience method to access elements previously packed using the [`pack_sequence_*`] methods,
995+
/// and is equivalent to calling [`get_bits_unchecked(index * n, n)`].
996+
/// It is thus safe to use this method with any index where `index * n + n` is in-bounds,
997+
/// and any size n <= 64.
998+
///
999+
/// # Panics
1000+
/// If the element is out of bounds, the function will either return unpredictable data or panic.
1001+
/// Use [`unpack_element`] for a checked version of this function.
1002+
///
1003+
/// [`pack_sequence_*`]: BitVec::pack_sequence_u64
1004+
/// [`get_bits_unchecked(index * n, n)`]: BitVec::get_bits_unchecked
1005+
#[must_use]
1006+
#[allow(clippy::inline_always)]
1007+
#[inline(always)] // to gain optimization if n is constant
1008+
pub fn unpack_element_unchecked(&self, index: usize, n: usize) -> u64 {
1009+
self.get_bits_unchecked(index * n, n)
1010+
}
1011+
9611012
/// Return the number of ones in the bit vector. Since the bit vector doesn't store additional
9621013
/// metadata, this value is calculated. Use [`RsVec`] for constant-time rank operations.
9631014
///

src/bit_vec/tests.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,3 +608,17 @@ fn test_from_conversion() {
608608
assert_eq!(bv.get_bits(0, 64), Some(0));
609609
assert_eq!(bv.get_bits(64, 64), Some(u64::MAX));
610610
}
611+
612+
#[test]
613+
fn test_unpack() {
614+
let sequence = [10, 12, 0, 1000, 1, 0, 1, 0];
615+
let bv = BitVec::pack_sequence_u64(&sequence, 10);
616+
617+
for (i, &val) in sequence.iter().enumerate() {
618+
assert_eq!(bv.unpack_element(i, 10), Some(val));
619+
assert_eq!(bv.unpack_element_unchecked(i, 10), val);
620+
}
621+
622+
assert_eq!(bv.unpack_element(8, 10), None);
623+
assert_eq!(bv.unpack_element(1000, 10), None);
624+
}

0 commit comments

Comments
 (0)