Feat/zero copy slice - #13
Conversation
Move src/bit_string/traits/ to src/traits/ so BitsEdit, BitsArith, and BitsEq are accessible at the crate root — [u64] operations are not specific to BitString and other types can reuse them. Add src/bit_str.rs — a zero-copy BitStr<'a> view type: - 24 bytes: &BitString + start offset + bit_len - slice, expand_left, expand_right (all zero-copy) - get, starts_with, ends_with, find, rfind, contains - strip_prefix, strip_suffix - iter, display, debug, PartialEq - to_bit_string() for materialization Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
Implement BitStr access methods (get, first, last, get_chunk) with boundary masking to prevent leaking source bits beyond the view. Add BitStr predicates (is_empty implemented, rest stubbed) and zero-copy slice via UsizeCO (non-empty invariant encoded in type). Split BitString access into impls_for_access (get/get_chunk) and impls_for_predicates (any/all/is_empty) to match BitStr structure. Add 17 tests covering empty views, offset views, cross-word boundaries, unaligned reads, and chunk non-leakage. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
Add count_ones() and count_zeros() to BitStr, mirroring the BitString API. Word-aligned views delegate directly to the SIMD-accelerated [64]::count_ones. Unaligned views handle the first partial word via scalar popcnt, dispatch middle full words through the SIMD path, then handle the last partial word. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
Implement any/all/is_all_zeros/is_all_ones via count_ones, matching the BitString pattern. Complete slice_from and slice_until with clamping semantics, plus 22 tests covering empty views, chaining, offset views, and mixed usage. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
Add Iter struct implementing Iterator, DoubleEndedIterator, ExactSizeIterator, and FusedIterator for BitStr. Also provides IntoIterator on &BitStr for for-loop ergonomics and to_bool_vec(). 14 tests covering full views, offset views, empty views, cross-word boundaries, and fused semantics. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
…, contains, find, rfind, strip Implement the full matching suite for BitStr by delegating to BitString::bits_equal_at with the view start offset added. Needle type is &BitString, matching the BitString API convention. - matches_at / starts_with / ends_with: O(word_len) via SIMD word equality - contains / find / rfind: position-scanning with bits_equal_at verification - strip_prefix / strip_suffix: return Option<BitStr> sub-view 38 tests covering basic matching, empty needle, too-long needle, offset views, cross-word boundaries, and chained views. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
Move the matches_at/starts_with/ends_with impl block and its tests from impls_for_matching.rs into a dedicated impls_for_matches_at.rs, matching the BitString module structure. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
Move three SIMD find-core functions from bit_string impls_for_find to traits/bits_find, and define a BitsFind trait on [u64] with find_any_candidate, find_first_word, and find_last_word. BitStr::find/rfind now use the SIMD candidate pre-filter: slice the source words from the view's start word, pass start_offset+bit_len as the effective length, then shift candidate positions back. This matches the BitString optimization path. Both BitString and BitStr now share the same SIMD-accelerated search via the trait — no code duplication. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
…erior Previously the unaligned path passed the whole words[start_word..] to SIMD with start_offset in the bit_len. The SIMD scan would test positions 0..start_offset that lie outside the view, requiring per-candidate filtering. Now the unaligned path does: 1. Scalar scan of the first partial word (at most 63 positions) 2. SIMD on aligned words[start_word+1..] with bit_len=remaining, zero filtering — every candidate is in-bounds. 3. rfind does SIMD first (reverse), then scalar fallback. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
Change all read-only matching methods to take &BitStr needles: - matches_at / starts_with / ends_with - contains / find / rfind - strip_prefix / strip_suffix bits_equal_at now handles dual-offset comparison: - Sub-word (<= 64 bits): read_word_at on both sides + mask - Multi-word, needle aligned: SIMD eq_words on haystack - Multi-word, both misaligned: scalar word-at-a-time (rare) This eliminates allocations when using BitStr views as needles, following the &str pattern from std. BitString users pass &bs.as_bitstr() for zero-cost conversion. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
…es to as_bit_str() BitStr is Copy (24 bytes), so passing by value is cleaner and costs nothing after inlining. All matching methods now take BitStr<'_> instead of &BitStr<'_>. BitString's matching methods (matches_at, starts_with, ends_with, contains, find, rfind, strip_prefix, strip_suffix) now delegate entirely to self.as_bit_str(), removing ~130 lines of duplicated SIMD logic. Tests: moved tests_for_bits_equal_at to BitStr side; split combined tests_for_matches_at into separate files per method. Benchmarks updated. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
Display writes '1'/'0' for each bit in the view, reusing BitStr::get()
which already accounts for the view offset. Debug wraps Display output
in BitStr("...") format, matching BitString's debug style.
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DeepSeek AI <service@deepseek.com>
BitStr equality: compare bit_len first, then delegate to bits_equal_at which handles SIMD on both sides. Different sources and offsets are supported — two views are equal iff their bit contents match. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
Copy the bits in a BitStr view into a new owned BitString via BitString::slice, which performs a word-level copy from the source. Empty views short-circuit to BitString::new(). Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
Hash implementation consistent with Eq: hashes bit_len first, then each full word via read_word_at (handling offset), and masks the last partial word so unused bits don't affect the hash. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
When the view starts at a word boundary, hash full words as a &[u64] slice instead of iterating word-by-word. For unaligned views, hash the first partial word via read_word_at, then hash the middle aligned words as a contiguous slice, and finally the tail partial word. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
[<B0>u64]::hash injects write_length_prefix which makes aligned and unaligned views of the same content produce different hashes. Hash each full word individually instead, so both code paths emit the same Hasher call sequence. Adds regression test: unaligned view vs aligned roundtrip must hash equally. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
Remove derive(Hash) from BitString and add a manual impl that delegates to self.as_bit_str().hash(state), ensuring hash(bit_string) always equals hash(bit_string.as_bit_str()). Tests consolidated into bit_str/impls_for_hash/tests_for_hash.rs. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
BitOrd trait (src/traits/bit_ord.rs): - bitwise_cmp(self, other) on u64 — LSB-first lexicographic ordering via trailing_zeros (tzcnt), shared by all SIMD backends. BitsOrd trait (src/traits/bits_ord.rs): - cmp_words(&self, other, count, offset) on [u64] — follows the same pattern as BitsEq: a single method taking self's intra-word offset, with other always word-aligned. Dispatches to aligned or unaligned SIMD based on offset % 64. SIMD backends (AVX2 4×u64 / SSE2 2×u64 / NEON 2×u64): - Aligned: pcmpeqq + movemask + trailing_ones to locate first diff. - Unaligned: shifted-window (src[i]>>shift)|(src[i+1]<<(64-shift)). - Both backends tested against scalar oracle via proptest. BitStr::cmp dispatch (src/bit_str/impls_for_ord.rs): - Follows bits_equal_at pattern: prefer word-aligned side as needle. - Falls back to scalar read_word_at when both sides are unaligned (rare). Benchmarks: benches/hash.rs + benches/ord.rs — compare BitString, BitStr (unaligned), and String/str across 64/4096/65536 bits. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DeepSeek AI <service@deepseek.com>
BitString now supports lexicographic comparison via PartialOrd and Ord. Implementation follows the same pattern as Hash — both traits delegate to as_bit_str() for zero-code-duplication. - src/bit_string/impls_for_ord.rs: PartialOrd + Ord impl (inline delegation) - src/bit_string/impls_for_ord/tests_for_ord.rs: 10 tests (sort, min/max, cross-word, delegation consistency) - src/bit_string.rs: register impls_for_ord module Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Merging this PR will improve performance by 15.76%
|
The CodSpeed run_command now filters for both 'bit_string' and 'bit_str' benchmark names, instead of only 'bit_string'. This ensures SIMD-accelerated BitStr benchmarks (ord, hash, matching, etc.) are also tracked for performance regressions. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
The previous comma-separated 'bit_string,bit_str' was treated as a single literal filter pattern by cargo-codspeed, which uses substring matching. Since no benchmark name contains a comma, zero benches were detected. Use the common prefix 'bit_' which matches both bit_string and bit_str benchmarks (136 total) without matching competitors (bitvec_simd, string). Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepSeek AI <service@deepseek.com>
No description provided.