From 84ed752b78c5d5e6f89007ed0d48f42b035f4035 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Tue, 12 May 2026 22:30:45 +0800 Subject: [PATCH] perf: optimize packed_seq sub() with direct bit-slice copying Replaces per-nucleotide iteration with direct bit-slice copying via `bitvec`. This eliminates per-element decoding overhead and intermediate allocations by computing the target byte length, copying the packed bit range `[start*2, end*2)` directly into a pre-allocated buffer, and constructing the result in a single pass. --- src/obikseq/src/packed_seq.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/obikseq/src/packed_seq.rs b/src/obikseq/src/packed_seq.rs index 3acac76..601e667 100644 --- a/src/obikseq/src/packed_seq.rs +++ b/src/obikseq/src/packed_seq.rs @@ -261,8 +261,13 @@ impl PackedSeq { /// Extract nucleotides `[start, end)` as a new [`PackedSeq`]. Allocates. pub fn sub(&self, start: usize, end: usize) -> Self { debug_assert!(end > start && end <= self.seql()); - let nucs: Vec = (start..end).map(|i| self.nucleotide(i)).collect(); - Self::from_nucleotides(&nucs) + let seql = end - start; + let n = (seql + 3) / 4; + let mut out = vec![0u8; n]; + let src = self.seq.view_bits::(); + let dst = out.view_bits_mut::(); + dst[..seql * 2].copy_from_bitslice(&src[start * 2..end * 2]); + Self::new(count_to_tail(seql), out.into_boxed_slice()) } /// Serialise one chunk to binary.