compressed_intvec/fixed/
mod.rs

1//! A generic, compressed, and randomly accessible vector with fixed-width encoding.
2//!
3//! This module provides [`FixedVec`] and its thread-safe counterpart, [`AtomicFixedVec`],
4//! two data structures for storing sequences of integers where each element is encoded
5//! using the same number of bits. This strategy, known as fixed-width encoding,
6//! is suitable for data where values are bounded within a known range, as it
7//! allows for O(1) random access by directly calculating the memory location of any element.
8//!
9//! # Core Concepts
10//!
11//! The design is generic over four parameters: `FixedVec<T, W, E, B>`.
12//! - `T`: The element type as seen by the user (e.g., [`u32`], [`i16`]), constrained by the [`Storable`] trait.
13//! - `W`: The underlying unsigned integer type used for storage (e.g., [`u64`], [`usize`]), constrained by the [`Word`] trait.
14//! - `E`: The [`Endianness`] (e.g., [`LE`] or [`BE`]) for bit-level operations.
15//! - `B`: The backing buffer, which abstracts over ownership. This allows [`FixedVec`] to be an owned container (e.g., `Vec<W>`) or a zero-copy, borrowed view (e.g., `&[W]`).
16//!
17//! ### Immutability and Zero-Copy Views
18//! Immutable access is performed in O(1) time by calculating an element's bit-level offset.
19//! Structures like [`FixedVecSlice`](slice::FixedVecSlice) provide zero-copy views into a vector, representing
20//! a sub-region of the data without requiring data duplication or new allocations.
21//!
22//! ### Mutability via Proxy Objects
23//! Direct mutable references (`&mut T`) to individual bit-packed elements are not possible, as
24//! elements do not align with byte boundaries and may not even exist as discrete entities in memory.
25//! Instead, mutability is managed through the proxy object pattern. Methods like [`at_mut`](FixedVec::at_mut) return a temporary proxy ([`MutProxy`]) that holds a decoded copy of the value.
26//! Modifications are applied to this copy, and the value is automatically encoded and written
27//! back into the vector's bitstream when the proxy object goes out of scope (i.e., is dropped).
28//!
29//! # Core Data Structures
30//!
31//! - [`FixedVec`]: The primary implementation for single-threaded contexts.
32//! - [`AtomicFixedVec`]: A thread-safe variant for concurrent applications. It provides an
33//!   API analogous to Rust's standard atomic types ([`load`](AtomicFixedVec::load), [`store`](AtomicFixedVec::store), [`fetch_add`](AtomicFixedVec::fetch_add), etc.).
34//!   It uses lock-free atomic instructions for elements contained within a single machine word and
35//!   a fine-grained locking strategy (lock striping) for elements that span word boundaries. This
36//!   hybrid approach ensures thread safety for any `bit-width` configuration.
37//!
38//! # Main Components
39//!
40//! - [`FixedVec`] and [`AtomicFixedVec`]
41//! - [`BitWidth`]: An enum to control the bit-width selection strategy. Options include:
42//!     - [`BitWidth::Minimal`]: Selects the minimal bit-width required.
43//!     - [`BitWidth::PowerOfTwo`]: Rounds up to the nearest power of two.
44//!     - [`BitWidth::Explicit`]: Allows specifying a fixed bit-width.
45//! - **Builders**: [`FixedVecBuilder`](builder::FixedVecBuilder) and [`FixedVecFromIterBuilder`](builder::FixedVecFromIterBuilder) 
46//! - **Slices**: [`FixedVecSlice`](slice::FixedVecSlice) for creating immutable or mutable views.
47//!
48//! # Examples
49//!
50//! Create a [`FixedVec`] from a slice of data. The builder will
51//! automatically determine the minimal number of bits required.
52//!
53//! ```
54//! use compressed_intvec::fixed::{FixedVec, UFixedVec};
55//!
56//! // The numbers 0-7 can all be represented in 3 bits.
57//! let data: Vec<u32> = (0..8).collect();
58//!
59//! // The builder infers that `bit_width` should be 3.
60//! let vec: UFixedVec<u32> = FixedVec::builder()
61//!     .build(&data)
62//!     .unwrap();
63//!
64//! assert_eq!(vec.len(), 8);
65//! assert_eq!(vec.bit_width(), 3);
66//! assert_eq!(vec.get(5), Some(5));
67//! ```
68//!
69//! ## Storing Signed Integers
70//!
71//! [`FixedVec`] can store signed integers. The underlying storage uses zig-zag encoding,
72//! which maps small negative and positive numbers to small unsigned integers.
73//!
74//! ```
75//! use compressed_intvec::fixed::{FixedVec, SFixedVec};
76//!
77//! // The values range from -2 to 1. Zig-zag encoding maps these to
78//! // unsigned values, so the maximum value is 3, which
79//! // requires 2 bits.
80//! let data: &[i16] = &[-2, -1, 0, 1];
81//! let vec: SFixedVec<i16> = FixedVec::builder().build(data).unwrap();
82//!
83//! assert_eq!(vec.bit_width(), 2);
84//! assert_eq!(vec.get(0), Some(-2));
85//! assert_eq!(vec.get(3), Some(1));
86//! ```
87//!
88//! # Implementation Notes
89//!
90//! To ensure safe and efficient memory access, [`FixedVec`] adds one padding
91//! word at the end of its storage buffer. This padding prevents out-of-bounds
92//! reads in methods like [`get_unchecked`](FixedVec::get_unchecked) and is a
93//! prerequisite for unaligned access with [`get_unaligned_unchecked`](FixedVec::get_unaligned_unchecked).
94//! The builders handle this padding automatically. When creating a [`FixedVec`] from raw parts,
95//! it is the caller's responsibility to ensure this padding is present.
96//!
97//! # Common Type Aliases
98//!
99//! To simplify usage, this crate provides several type aliases for common [`FixedVec`]
100//! configurations. In most cases, you should prefer using these aliases over the
101//! fully generic `FixedVec<T, W, E, B>` struct.
102//!
103//! ### General-Purpose Aliases
104//!
105//! These aliases use [`usize`] for the storage word, which is often the most
106//! efficient choice for the target architecture.
107//!
108//! - [`UFixedVec<T>`]: For unsigned integers (e.g., [`u8`], [`u16`], [`u32`]).
109//! - [`SFixedVec<T>`]: For signed integers (e.g., [`i8`], [`i16`], [`i32`]).
110//!
111//! ### Concrete Aliases for [`u64`]/[`i64`]
112//!
113//! These aliases are specialized for [`u64`]/[`i64`] elements stored in [`u64`] words:
114//!
115//! - [`LEFixedVec`]: [`u64`] elements, Little-Endian.
116//! - [`BEFixedVec`]: [`u64`] elements, Big-Endian.
117//! - [`LESFixedVec`]: [`i64`] elements, Little-Endian.
118//! - [`BESFixedVec`]: [`i64`] elements, Big-Endian.
119//!
120//! The [`atomic`] module provides a similar set of aliases like [`UAtomicFixedVec`]
121//! and [`SAtomicFixedVec`].
122
123// Declare and export submodules.
124#[macro_use]
125pub mod macros;
126pub mod builder;
127pub mod iter;
128pub mod iter_mut;
129pub mod parallel;
130pub mod proxy;
131pub mod slice;
132pub mod traits;
133
134pub mod atomic;
135
136// Conditionally compile the serde module.
137#[cfg(feature = "serde")]
138mod serde;
139
140use dsi_bitstream::{
141    prelude::Endianness,
142    traits::{BE, LE},
143};
144use mem_dbg::{MemDbg, MemSize};
145use num_traits::ToPrimitive;
146use std::{error::Error as StdError, fmt, iter::FromIterator, marker::PhantomData};
147use traits::{Storable, Word};
148
149use crate::fixed::{proxy::MutProxy, traits::DefaultParams};
150
151// Re-export atomic aliases for convenience.
152pub use atomic::{AtomicFixedVec, SAtomicFixedVec, UAtomicFixedVec};
153
154// Type aliases for common `FixedVec` configurations.
155
156/// A [`FixedVec`] for unsigned integers with a `usize` word and Little-Endian layout.
157///
158/// This is a convenient alias for a common configuration. The element type `T`
159/// can be any unsigned integer that implements [`Storable`], such as `u8`, `u16`,
160/// `u32`, [`u64`], `u128`, or `usize`.
161pub type UFixedVec<T, B = Vec<usize>> = FixedVec<T, usize, LE, B>;
162
163/// A [`FixedVec`] for signed integers with a `usize` word and Little-Endian layout.
164///
165/// This alias is suitable for general-purpose use with signed types like `i8`,
166/// `i16`, `i32`, [`i64`], `i128`, or `isize`.
167pub type SFixedVec<T, B = Vec<usize>> = FixedVec<T, usize, LE, B>;
168
169// --- Concrete Aliases for [`u64`]/[`i64`] elements ---
170// These are provided for common use cases and backward compatibility.
171
172/// A [`FixedVec`] for [`u64`] elements with a [`u64`] backend and Little-Endian layout.
173pub type LEFixedVec<B = Vec<u64>> = FixedVec<u64, u64, LE, B>;
174/// A [`FixedVec`] for [`i64`] elements with a [`u64`] backend and Little-Endian layout.
175pub type LESFixedVec<B = Vec<u64>> = FixedVec<i64, u64, LE, B>;
176
177/// A [`FixedVec`] for [`u64`] elements with a [`u64`] backend and Big-Endian layout.
178pub type BEFixedVec<B = Vec<u64>> = FixedVec<u64, u64, BE, B>;
179/// A [`FixedVec`] for [`i64`] elements with a [`u64`] backend and Big-Endian layout.
180pub type BESFixedVec<B = Vec<u64>> = FixedVec<i64, u64, BE, B>;
181
182/// Specifies the strategy for determining the number of bits for each integer.
183///
184/// This enum controls how the bit width of a [`FixedVec`] is determined during
185/// its construction. The choice of strategy involves a trade-off between memory
186/// usage and random access performance.
187///
188/// # Performance Considerations
189///
190/// - **[`Minimal`](BitWidth::Minimal) vs. [`PowerOfTwo`](BitWidth::PowerOfTwo)**: While [`Minimal`](BitWidth::Minimal) provides the most compact
191///   storage, [`PowerOfTwo`](BitWidth::PowerOfTwo) can offer better performance for certain operations.
192///   When the `bit_width` is a power of two (e.g., 8, 16, 32) and aligns with
193///   word boundaries, some in-place operations like [`map_in_place`](FixedVec::map_in_place) can use a
194///   faster, word-at-a-time algorithm.
195///
196/// - **[`Explicit`](BitWidth::Explicit)**: This is the fastest strategy at construction time, as it
197///   avoids the need to iterate through the input data to find the maximum
198///   value. Use this when the required bit width is known in advance.
199#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
200pub enum BitWidth {
201    /// Use the minimum number of bits required to store the largest value.
202    ///
203    /// This strategy analyzes the input data to find the maximum value and sets
204    /// the bit width accordingly. It ensures the most compact memory representation.
205    #[default]
206    Minimal,
207
208    /// Round the bit width up to the next power of two (e.g., 8, 16, 32).
209    ///
210    /// This strategy can improve random access performance for some in-place
211    /// operations, as they can be implemented more efficiently with bit-shift operations on aligned data.
212    PowerOfTwo,
213
214    /// Use a specific number of bits.
215    ///
216    /// This strategy enforces a user-defined bit width. If any value in the
217    /// input data exceeds what can be stored in this many bits, the build
218    /// process will fail.
219    Explicit(usize),
220}
221
222/// Defines errors that can occur during [`FixedVec`] operations.
223#[derive(Debug)]
224pub enum Error {
225    /// A value in the input data is too large to be stored with the configured
226    /// bit width.
227    ValueTooLarge {
228        /// The value that could not be stored.
229        value: u128,
230        /// The index of the value in the input data.
231        index: usize,
232        /// The configured number of bits.
233        bit_width: usize,
234    },
235    /// A parameter is invalid for the requested operation.
236    ///
237    /// This typically occurs if `bit_width` is larger than the storage word size
238    /// or if a provided buffer is too small.
239    InvalidParameters(String),
240}
241
242impl fmt::Display for Error {
243    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
244        match self {
245            Error::ValueTooLarge {
246                value,
247                index,
248                bit_width,
249            } => write!(
250                f,
251                "value {value} at index {index} does not fit in {bit_width} bits"
252            ),
253            Error::InvalidParameters(s) => write!(f, "Invalid parameters: {s}"),
254        }
255    }
256}
257
258impl StdError for Error {}
259
260/// A compressed vector of integers with fixed-width encoding.
261///
262/// [`FixedVec`] stores a sequence of integers where each element is encoded using
263/// the same number of bits. This allows for O(1) random access by calculating
264/// the memory location of any element. It is suitable for data where values are
265/// bounded within a known range.
266///
267/// # Type Parameters
268///
269/// - `T`: The integer type for the elements (e.g., `u32`, `i16`). It must
270///   implement the [`Storable`] trait.
271/// - `W`: The underlying storage word (e.g., [`u64`], `usize`). It must implement
272///   the [`Word`] trait.
273/// - `E`: The [`Endianness`] (e.g., [`LE`] or [`BE`]) for bit-level operations.
274/// - `B`: The backend storage buffer, such as `Vec<W>` for an owned vector or
275///   `&[W]` for a borrowed view.
276///
277/// For common configurations, several [type aliases] are provided.
278///
279/// [type aliases]: crate::fixed#type-aliases
280#[derive(Debug, Clone, MemDbg, MemSize)]
281pub struct FixedVec<T: Storable<W>, W: Word, E: Endianness, B: AsRef<[W]> = Vec<W>> {
282    /// The underlying storage for the bit-packed data.
283    pub(crate) bits: B,
284    /// The number of bits used to encode each element.
285    pub(crate) bit_width: usize,
286    /// A bitmask with the lowest `bit_width` bits set to one.
287    pub(crate) mask: W,
288    /// The number of elements in the vector.
289    pub(crate) len: usize,
290    /// Zero-sized markers for the generic type parameters `T`, `W`, and `E`.
291    pub(crate) _phantom: PhantomData<(T, W, E)>,
292}
293
294// [`FixedVec`] builder implementation.
295impl<T, W, E> FixedVec<T, W, E, Vec<W>>
296where
297    T: Storable<W>,
298    W: Word,
299    E: Endianness,
300    dsi_bitstream::impls::BufBitWriter<E, dsi_bitstream::impls::MemWordWriterVec<W, Vec<W>>>:
301        dsi_bitstream::prelude::BitWrite<E, Error = std::convert::Infallible>,
302{
303    /// Creates a builder for constructing a [`FixedVec`] from a slice.
304    ///
305    /// The builder provides methods to customize the vector's properties, such
306    /// as the [`BitWidth`] strategy.
307    ///
308    /// # Examples
309    ///
310    /// ```
311    /// use compressed_intvec::fixed::{FixedVec, BitWidth, UFixedVec};
312    ///
313    /// let data: &[u32] = &[10, 20, 30, 40, 50];
314    /// let vec: UFixedVec<u32> = FixedVec::builder()
315    ///     .bit_width(BitWidth::Minimal)
316    ///     .build(data)
317    ///     .unwrap();
318    ///
319    /// assert_eq!(vec.get(1), Some(20));
320    /// ```
321    pub fn builder() -> builder::FixedVecBuilder<T, W, E> {
322        builder::FixedVecBuilder::new()
323    }
324
325    /// Creates a builder for constructing a [`FixedVec`] from an iterator.
326    ///
327    /// This builder is suitable for large datasets provided by an iterator,
328    /// as it processes the data in a streaming fashion.
329    ///
330    /// # Arguments
331    ///
332    /// * `iter`: An iterator that yields the integer values.
333    /// * `bit_width`: The number of bits to use for each element. This must be
334    ///   specified, as the builder cannot analyze the data in advance.
335    ///
336    /// # Examples
337    ///
338    /// ```
339    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
340    ///
341    /// let data = 0..100u32;
342    /// let vec: UFixedVec<u32> = FixedVec::from_iter_builder(data, 7)
343    ///     .build()
344    ///     .unwrap();
345    ///
346    /// assert_eq!(vec.len(), 100);
347    /// assert_eq!(vec.bit_width(), 7);
348    /// assert_eq!(vec.get(99), Some(99));
349    /// ```
350    pub fn from_iter_builder<I: IntoIterator<Item = T>>(
351        iter: I,
352        bit_width: usize,
353    ) -> builder::FixedVecFromIterBuilder<T, W, E, I> {
354        builder::FixedVecFromIterBuilder::new(iter, bit_width)
355    }
356
357    /// Creates an owned [`FixedVec`] from a slice of data.
358    ///
359    /// This method is a convenience wrapper around the builder API, using
360    /// the default bit width strategy ([`BitWidth::Minimal`]).
361    /// 
362    /// # Examples
363    /// 
364    /// ```rust
365    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
366    /// 
367    /// let data: &[u32] = &[10, 20, 30];
368    /// 
369    /// let vec: UFixedVec<u32> = FixedVec::from_slice(data).unwrap();
370    /// 
371    /// assert_eq!(vec.len(), 3);
372    /// assert_eq!(vec.bit_width(), 5); // 30 fits in 5 bits
373    /// assert_eq!(vec.get(0), Some(10));
374    /// ```
375    pub fn from_slice(slice: &[T]) -> Result<Self, Error> {
376        Self::builder().build(slice)
377    }
378}
379
380// Core immutable API.
381impl<T, W, E, B> FixedVec<T, W, E, B>
382where
383    T: Storable<W>,
384    W: Word,
385    E: Endianness,
386    B: AsRef<[W]>,
387{
388    /// Creates a [`FixedVec`] from its raw components.
389    ///
390    /// This constructor allows for the creation of a zero-copy view over an
391    /// existing buffer.
392    ///
393    /// # Errors
394    ///
395    /// Returns an [`Error::InvalidParameters`] if `bit_width` is larger than
396    /// the word size or if the `bits` buffer is too small to hold the specified
397    /// number of elements and the required padding.
398    ///
399    /// # Implementation Notes
400    ///
401    /// The provided `bits` buffer must contain at least one extra "padding"
402    /// word at the end. This padding is essential to prevent out-of-bounds
403    /// memory access in methods like `get_unchecked`.
404    ///
405    /// # Examples
406    ///
407    /// ```
408    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
409    ///
410    /// // 3 elements * 5 bits = 15 bits. This requires 1 data word.
411    /// // We need 1 extra word for padding.
412    /// let mut buffer = vec![0_usize; 2];
413    ///
414    /// // Manually encode data into the first word.
415    /// // 10 (01010), 20 (10100), 30 (11110)
416    /// buffer[0] = 0b11110_10100_01010;
417    ///
418    /// let vec = UFixedVec::<u32, _>::from_parts(&buffer, 3, 5).unwrap();
419    /// assert_eq!(vec.get(0), Some(10));
420    /// assert_eq!(vec.get(1), Some(20));
421    /// assert_eq!(vec.get(2), Some(30));
422    /// ```
423    pub fn from_parts(bits: B, len: usize, bit_width: usize) -> Result<Self, Error> {
424        if bit_width > <W as traits::Word>::BITS {
425            return Err(Error::InvalidParameters(format!(
426                "bit_width ({}) cannot be greater than the word size ({})",
427                bit_width,
428                <W as traits::Word>::BITS
429            )));
430        }
431
432        let total_bits = len * bit_width;
433        let data_words = total_bits.div_ceil(<W as traits::Word>::BITS);
434
435        // Essential safety check: ensure the buffer is large enough for the data
436        // AND the 1 padding word required.
437        if bits.as_ref().len() < data_words + 1 {
438            return Err(Error::InvalidParameters(format!(
439                "The provided buffer is too small. It has {} words, but {} data words + 1 padding word are required.",
440                bits.as_ref().len(),
441                data_words
442            )));
443        }
444
445        Ok(unsafe { Self::new_unchecked(bits, len, bit_width) })
446    }
447
448    /// Returns the number of elements in the vector.
449    #[inline]
450    pub fn len(&self) -> usize {
451        self.len
452    }
453
454    /// Returns `true` if the vector is empty.
455    #[inline]
456    pub fn is_empty(&self) -> bool {
457        self.len == 0
458    }
459
460    /// Returns the number of bits used to encode each element.
461    #[inline]
462    pub fn bit_width(&self) -> usize {
463        self.bit_width
464    }
465
466    /// Returns a read-only slice of the underlying storage words.
467    #[inline]
468    pub fn as_limbs(&self) -> &[W] {
469        self.bits.as_ref()
470    }
471
472    /// Returns a raw pointer to the start of the underlying buffer and its
473    /// length in words.
474    ///
475    /// # Safety
476    ///
477    /// The caller must ensure that the buffer is not mutated in a way that
478    /// violates the invariants of the [`FixedVec`] while the pointer is active.
479    pub fn as_raw_parts(&self) -> (*const W, usize) {
480        let slice = self.bits.as_ref();
481        (slice.as_ptr(), slice.len())
482    }
483
484    /// Creates a [`FixedVec`] from its raw components without performing checks.
485    ///
486    /// # Safety
487    ///
488    /// The caller must ensure that the following invariants are met:
489    /// 1. The `bits` buffer must be large enough to hold `len * bit_width` bits.
490    /// 2. The `bits` buffer must have at least one extra padding word at the end
491    ///    to prevent out-of-bounds reads during access.
492    /// 3. `bit_width` must not be greater than the number of bits in `W`.
493    pub(crate) unsafe fn new_unchecked(bits: B, len: usize, bit_width: usize) -> Self {
494        let mask = if bit_width == <W as traits::Word>::BITS {
495            W::max_value()
496        } else {
497            (W::ONE << bit_width) - W::ONE
498        };
499
500        Self {
501            bits,
502            len,
503            bit_width,
504            mask,
505            _phantom: PhantomData,
506        }
507    }
508
509    /// Returns the element at the specified index, or `None` if the index is
510    /// out of bounds.
511    ///
512    /// This operation is O(1).
513    ///
514    /// # Examples
515    ///
516    /// ```
517    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
518    ///
519    /// let data: &[u32] = &[10, 20, 30];
520    /// let vec: UFixedVec<u32> = FixedVec::builder().build(data).unwrap();
521    ///
522    /// assert_eq!(vec.get(1), Some(20));
523    /// assert_eq!(vec.get(3), None);
524    /// ```
525    #[inline]
526    pub fn get(&self, index: usize) -> Option<T> {
527        if index >= self.len {
528            return None;
529        }
530        Some(unsafe { self.get_unchecked(index) })
531    }
532
533    /// Returns the element at the specified index without bounds checking.
534    ///
535    /// # Safety
536    ///
537    /// Calling this method with an out-of-bounds `index` is undefined behavior.
538    /// The `index` must be less than the vector's `len`.
539    #[inline(always)]
540    pub unsafe fn get_unchecked(&self, index: usize) -> T {
541        debug_assert!(index < self.len);
542
543        let bits_per_word = <W as traits::Word>::BITS;
544        // Optimization: if bit_width matches word size, access is trivial.
545        if self.bit_width == bits_per_word {
546            let val = *self.as_limbs().get_unchecked(index);
547            // Apply endianness correction if needed.
548            let final_val = if E::IS_BIG { val.to_be() } else { val };
549            return <T as Storable<W>>::from_word(final_val);
550        }
551
552        // Calculate the bit position and word index for the element.
553        let bit_pos = index * self.bit_width;
554        let word_index = bit_pos / bits_per_word;
555        let bit_offset = bit_pos % bits_per_word;
556
557        let limbs = self.as_limbs();
558        let final_word: W;
559
560        // The logic is specialized for endianness to maximize performance.
561        if E::IS_LITTLE {
562            // Fast path: the element is fully contained within a single word.
563            if bit_offset + self.bit_width <= bits_per_word {
564                final_word = (*limbs.get_unchecked(word_index) >> bit_offset) & self.mask;
565            } else {
566                // Slow path: the element spans two words.
567                // Read the low part from the first word and the high part from the next.
568                let low = *limbs.get_unchecked(word_index) >> bit_offset;
569                let high = *limbs.get_unchecked(word_index + 1) << (bits_per_word - bit_offset);
570                final_word = (low | high) & self.mask;
571            }
572        } else {
573            // Big-Endian logic requires byte-swapping the words before extraction.
574            let word_hi = (*limbs.get_unchecked(word_index)).to_be();
575            if bit_offset + self.bit_width <= bits_per_word {
576                final_word = (word_hi << bit_offset) >> (bits_per_word - self.bit_width);
577            } else {
578                let word_lo = (*limbs.get_unchecked(word_index + 1)).to_be();
579                let bits_in_first = bits_per_word - bit_offset;
580                let high = word_hi << bit_offset >> (bits_per_word - bits_in_first);
581                let low = word_lo >> (bits_per_word - (self.bit_width - bits_in_first));
582                final_word = (high << (self.bit_width - bits_in_first)) | low;
583            }
584        }
585        <T as Storable<W>>::from_word(final_word)
586    }
587
588    /// Returns the element at `index` using unaligned memory access.
589    ///
590    /// This method can be significantly faster for random access. It performs a
591    /// single, potentially unaligned read of a [`Word`] and extracts the value.
592    ///
593    /// # Performance
594    ///
595    /// This method is generally the fastest way to perform random reads on
596    /// Little-Endian architectures, especially when the `bit_width` is not a
597    /// power of two.
598    ///
599    /// - [`get_unchecked`](Self::get_unchecked): May require reading one or two separate machine words
600    ///   and combining them with bit shifts. This is fast if the data is already
601    ///   in the CPU cache.
602    /// - [`get_unaligned_unchecked`](Self::get_unaligned_unchecked): Performs a single memory read that may
603    ///   cross word boundaries. It often results in fewer instructions and better throughput than the two
604    ///   separate reads of [`get_unchecked`](Self::get_unchecked), especially in memory-bound scenarios.
605    ///
606    ///
607    /// # Safety
608    ///
609    /// Calling this method with an out-of-bounds `index` is undefined behavior.
610    /// The [`FixedVec`] must have been constructed with sufficient padding (at
611    /// least one [`Word`]) to guarantee that the unaligned read does not go
612    /// past the allocated buffer. This padding is guaranteed by the default
613    /// builders.
614    ///
615    /// # Implementation Notes
616    ///
617    /// For Big-Endian, this method falls back to the standard [`get_unchecked`](Self::get_unchecked) implementation.
618    #[inline(always)]
619    pub unsafe fn get_unaligned_unchecked(&self, index: usize) -> T {
620        debug_assert!(index < self.len);
621
622        if E::IS_LITTLE {
623            let bits_per_word = <W as Word>::BITS;
624            if self.bit_width == bits_per_word {
625                return self.get_unchecked(index);
626            }
627
628            let bit_pos = index * self.bit_width;
629            let byte_pos = bit_pos / 8;
630            let bit_rem = bit_pos % 8;
631
632            let limbs_ptr = self.as_limbs().as_ptr() as *const u8;
633
634            // Perform an unaligned read from the calculated byte position.
635            let word: W = (limbs_ptr.add(byte_pos) as *const W).read_unaligned();
636            let extracted_word = word >> bit_rem;
637
638            <T as Storable<W>>::from_word(extracted_word & self.mask)
639        } else {
640            // For Big-Endian, the logic for unaligned reads is complex and
641            // architecture-dependent. Fall back to the standard `get_unchecked`.
642            self.get_unchecked(index)
643        }
644    }
645
646    /// Returns an iterator over the elements of the vector.
647    ///
648    /// # Examples
649    ///
650    /// ```
651    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
652    ///
653    /// let data: &[u32] = &[10, 20, 30];
654    /// let vec: UFixedVec<u32> = FixedVec::builder().build(data).unwrap();
655    /// let mut iter = vec.iter();
656    ///
657    /// for (i, value) in iter.enumerate() {
658    ///     assert_eq!(Some(value), vec.get(i));
659    /// }
660    /// ```
661    pub fn iter(&self) -> iter::FixedVecIter<'_, T, W, E, B> {
662        iter::FixedVecIter::new(self)
663    }
664
665    /// Returns an unchecked iterator over the elements of the vector.
666    ///
667    /// # Safety
668    ///
669    /// The caller must ensure that the iterator is not advanced beyond the
670    /// vector's length.
671    pub unsafe fn iter_unchecked(&self) -> iter::FixedVecUncheckedIter<'_, T, W, E, B> {
672        iter::FixedVecUncheckedIter::new(self)
673    }
674
675    /// Creates an immutable view (slice) of a sub-region of the vector.
676    ///
677    /// Returns `None` if the specified range is out of bounds.
678    ///
679    /// # Arguments
680    /// * `start`: The starting index of the slice.
681    /// * `len`: The number of elements in the slice.
682    pub fn slice(&self, start: usize, len: usize) -> Option<slice::FixedVecSlice<&Self>> {
683        if start.saturating_add(len) > self.len {
684            return None;
685        }
686        Some(slice::FixedVecSlice::new(self, start..start + len))
687    }
688
689    /// Splits the vector into two immutable views at a given index.
690    ///
691    /// Returns `None` if `mid` is out of bounds.
692    ///
693    /// # Arguments
694    /// * `mid`: The index at which to split the vector.
695    pub fn split_at(
696        &self,
697        mid: usize,
698    ) -> Option<(slice::FixedVecSlice<&Self>, slice::FixedVecSlice<&Self>)> {
699        if mid > self.len {
700            return None;
701        }
702        let left = slice::FixedVecSlice::new(self, 0..mid);
703        let right = slice::FixedVecSlice::new(self, mid..self.len);
704        Some((left, right))
705    }
706
707    /// Returns an iterator over non-overlapping chunks of the vector.
708    ///
709    /// Each chunk is a [`FixedVecSlice`] of length `chunk_size`, except for the
710    /// last chunk, which may be shorter.
711    ///
712    /// # Panics
713    ///
714    /// Panics if `chunk_size` is 0.
715    ///
716    /// [`FixedVecSlice`]: slice::FixedVecSlice
717    pub fn chunks(&self, chunk_size: usize) -> iter::Chunks<'_, T, W, E, B> {
718        iter::Chunks::new(self, chunk_size)
719    }
720
721    /// Returns an iterator over all contiguous windows of length `size`.
722    ///
723    /// The windows overlap. If the vector is shorter than `size`, the iterator
724    /// returns no values.
725    ///
726    /// # Panics
727    ///
728    /// Panics if `size` is 0.
729    ///
730    /// # Examples
731    ///
732    /// ```
733    /// use compressed_intvec::fixed_vec;
734    ///
735    /// let vec = fixed_vec![1u32, 2, 3, 4, 5];
736    /// let mut windows = vec.windows(3);
737    ///
738    /// let slice1 = vec.slice(0, 3).unwrap();
739    /// let slice2 = vec.slice(1, 3).unwrap();
740    /// let slice3 = vec.slice(2, 3).unwrap();
741    ///
742    /// assert_eq!(windows.next().unwrap(), slice1);
743    /// assert_eq!(windows.next().unwrap(), slice2);
744    /// assert_eq!(windows.next().unwrap(), slice3);
745    /// assert!(windows.next().is_none());
746    /// ```
747    pub fn windows(&self, size: usize) -> iter::Windows<'_, T, W, E, B> {
748        assert!(size != 0, "window size cannot be zero");
749        iter::Windows::new(self, size)
750    }
751
752    /// Returns a raw pointer to the storage word containing the start of an element.
753    ///
754    /// This method returns a pointer to the [`Word`] in the backing buffer where
755    /// the data for the element at `index` begins.
756    ///
757    /// Returns `None` if `index` is out of bounds.
758    ///
759    /// # Safety
760    ///
761    /// This method is safe as it only returns a raw pointer. Dereferencing the
762    /// pointer is `unsafe`. The caller must ensure that the pointer is not used
763    /// after the [`FixedVec`] is dropped or modified.
764    pub fn addr_of(&self, index: usize) -> Option<*const W> {
765        if index >= self.len {
766            return None;
767        }
768
769        let bit_pos = index * self.bit_width;
770        let word_idx = bit_pos / <W as Word>::BITS;
771
772        let limbs = self.as_limbs();
773        if word_idx < limbs.len() {
774            Some(limbs.as_ptr().wrapping_add(word_idx))
775        } else {
776            None
777        }
778    }
779
780    /// Hints to the CPU to prefetch the data for the element at `index` into cache.
781    ///
782    /// This method uses an intrinsic to reduce memory latency for predictable
783    /// access patterns. It only has an effect on architectures that support it
784    /// (e.g., x86, x86-64) and compiles to a no-op on other platforms.
785    pub fn prefetch(&self, index: usize) {
786        if index >= self.len {
787            return;
788        }
789
790        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
791        {
792            use std::arch::x86_64::{_mm_prefetch, _MM_HINT_T0};
793
794            let bit_pos = index * self.bit_width;
795            let byte_pos = bit_pos / 8;
796
797            let limbs_ptr = self.as_limbs().as_ptr() as *const i8;
798
799            // SAFETY: Bounds check on `index` ensures `byte_pos` is within the
800            // allocated buffer (including padding). The pointer is valid.
801            unsafe {
802                // Prefetch into all cache levels (a good general-purpose default).
803                _mm_prefetch(limbs_ptr.add(byte_pos), _MM_HINT_T0);
804            }
805        }
806    }
807
808    /// Binary searches this vector for a given element.
809    ///
810    /// If the value is found, returns `Ok(usize)` with the index of the
811    /// matching element. If the value is not found, returns `Err(usize)` with
812    /// the index where the value could be inserted to maintain order.
813    ///
814    /// # Examples
815    ///
816    /// ```
817    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
818    ///
819    /// let data: &[u32] = &[10, 20, 30, 40, 50];
820    /// let vec: UFixedVec<u32> = FixedVec::builder().build(data).unwrap();
821    ///
822    /// assert_eq!(vec.binary_search(&30), Ok(2));
823    /// assert_eq!(vec.binary_search(&35), Err(3));
824    /// ```
825    pub fn binary_search(&self, value: &T) -> Result<usize, usize>
826    where
827        T: Ord,
828    {
829        let mut low = 0;
830        let mut high = self.len();
831
832        while low < high {
833            let mid = low + (high - low) / 2;
834            let mid_val = unsafe { self.get_unchecked(mid) };
835
836            match mid_val.cmp(value) {
837                std::cmp::Ordering::Less => low = mid + 1,
838                std::cmp::Ordering::Equal => return Ok(mid),
839                std::cmp::Ordering::Greater => high = mid,
840            }
841        }
842        Err(low)
843    }
844
845    /// Binary searches this vector with a key extraction function.
846    ///
847    /// This method is useful when searching for a value of a different type
848    /// than the elements of the slice. The function `f` is used to extract a
849    /// key of type `K` from an element, which is then compared to `key`.
850    pub fn binary_search_by_key<K: Ord, F>(&self, key: &K, mut f: F) -> Result<usize, usize>
851    where
852        F: FnMut(T) -> K,
853    {
854        self.binary_search_by(|probe| f(*probe).cmp(key))
855    }
856
857    /// Binary searches this vector with a custom comparison function.
858    ///
859    /// The comparator function `f` should return an `Ordering` indicating
860    /// the relation of a probe element to the value being searched for.
861    ///
862    /// # Examples
863    ///
864    /// ```
865    /// use compressed_intvec::fixed_vec;
866    /// use std::cmp::Ordering;
867    ///
868    /// let vec = fixed_vec![0u32, 1, 1, 2, 3];
869    ///
870    /// // Search for a value by comparing it to the probe.
871    /// let result = vec.binary_search_by(|probe| probe.cmp(&1));
872    /// assert!(matches!(result, Ok(1) | Ok(2)));
873    ///
874    /// let result_not_found = vec.binary_search_by(|probe| probe.cmp(&4));
875    /// assert_eq!(result_not_found, Err(5));
876    /// ```
877    pub fn binary_search_by<F>(&self, mut f: F) -> Result<usize, usize>
878    where
879        F: FnMut(&T) -> std::cmp::Ordering,
880    {
881        let mut low = 0;
882        let mut high = self.len();
883
884        while low < high {
885            let mid = low + (high - low) / 2;
886            // SAFETY: The loop invariants ensure `mid` is always in bounds.
887            let mid_val = unsafe { self.get_unchecked(mid) };
888
889            match f(&mid_val) {
890                std::cmp::Ordering::Less => low = mid + 1,
891                std::cmp::Ordering::Equal => return Ok(mid),
892                std::cmp::Ordering::Greater => high = mid,
893            }
894        }
895        Err(low)
896    }
897
898    /// Returns the index of the partition point of the vector.
899    ///
900    /// The vector is partitioned according to the predicate `pred`. This means
901    /// all elements for which `pred` returns `true` are on the left of the
902    /// partition point, and all elements for which `pred` returns `false` are
903    /// on the right.
904    ///
905    /// # Examples
906    ///
907    /// ```
908    /// use compressed_intvec::fixed_vec;
909    ///
910    /// let vec = fixed_vec![0u32, 1, 2, 3, 4, 5];
911    ///
912    /// // Find the partition point for elements `< 3`.
913    /// let partition_idx = vec.partition_point(|&x| x < 3);
914    /// assert_eq!(partition_idx, 3);
915    /// ```
916    pub fn partition_point<P>(&self, mut pred: P) -> usize
917    where
918        P: FnMut(&T) -> bool,
919    {
920        let mut len = self.len();
921        let mut left = 0;
922
923        while len > 0 {
924            let half = len / 2;
925            let mid = left + half;
926            // SAFETY: The loop invariants ensure `mid` is always in bounds.
927            let value = unsafe { self.get_unchecked(mid) };
928
929            if pred(&value) {
930                left = mid + 1;
931                len -= half + 1;
932            } else {
933                len = half;
934            }
935        }
936        left
937    }
938}
939
940/// Allows iterating over a borrowed [`FixedVec`] (e.g., `for val in &my_vec`).
941impl<'a, T, W, E, B> IntoIterator for &'a FixedVec<T, W, E, B>
942where
943    T: Storable<W>,
944    W: Word,
945    E: Endianness,
946    B: AsRef<[W]>,
947{
948    type Item = T;
949    type IntoIter = iter::FixedVecIter<'a, T, W, E, B>;
950
951    fn into_iter(self) -> Self::IntoIter {
952        self.iter()
953    }
954}
955
956/// Allows iterating over an owned [`FixedVec`], consuming it.
957impl<T, W, E> IntoIterator for FixedVec<T, W, E, Vec<W>>
958where
959    T: Storable<W> + 'static,
960    W: Word,
961    E: Endianness,
962{
963    type Item = T;
964    type IntoIter = iter::FixedVecIntoIter<'static, T, W, E>;
965
966    /// Consumes the vector and returns an iterator over its elements.
967    fn into_iter(self) -> Self::IntoIter {
968        iter::FixedVecIntoIter::new(self)
969    }
970}
971
972impl<T, W, E> FromIterator<T> for FixedVec<T, W, E, Vec<W>>
973where
974    T: Storable<W>,
975    W: Word,
976    E: Endianness,
977    dsi_bitstream::impls::BufBitWriter<E, dsi_bitstream::impls::MemWordWriterVec<W, Vec<W>>>:
978        dsi_bitstream::prelude::BitWrite<E, Error = std::convert::Infallible>,
979{
980    /// Creates a [`FixedVec`] by collecting elements from an iterator.
981    ///
982    /// The bit width is determined automatically using the [`BitWidth::Minimal`]
983    /// strategy. This requires collecting the iterator into a temporary `Vec<T>`
984    /// to analyze its contents before compression.
985    ///
986    /// # Memory Usage
987    ///
988    /// Because this implementation must first collect all items into a temporary
989    /// `Vec<T>` to determine the optimal `bit_width`, it may lead to a temporary
990    /// peak in memory usage that is roughly double the size of the uncompressed
991    /// data.
992    ///
993    /// For very large datasets where this memory overhead is a concern, it is
994    /// recommended to use [`FixedVec::from_iter_builder`] instead. The builder
995    /// allows for streaming construction but requires the `bit_width` to be
996    /// specified manually.
997    ///
998    /// # Examples
999    ///
1000    /// ```
1001    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
1002    ///
1003    /// let data = 0u32..100;
1004    /// let vec: UFixedVec<u32> = data.collect();
1005    ///
1006    /// assert_eq!(vec.len(), 100);
1007    /// assert_eq!(vec.get(50), Some(50));
1008    /// ```
1009    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1010        let data: Vec<T> = iter.into_iter().collect();
1011        Self::builder().build(&data).unwrap()
1012    }
1013}
1014
1015impl<T, W, E> Default for FixedVec<T, W, E, Vec<W>>
1016where
1017    T: Storable<W>,
1018    W: Word,
1019    E: Endianness,
1020{
1021    /// Creates an empty [`FixedVec`] with a default `bit_width` of 1.
1022    fn default() -> Self {
1023        // SAFETY: An empty vector with a valid bit_width is always safe.
1024        unsafe { Self::new_unchecked(Vec::new(), 0, 1) }
1025    }
1026}
1027
1028// Methods for owned vectors (`B = Vec<W>`).
1029impl<T, W, E> FixedVec<T, W, E, Vec<W>>
1030where
1031    T: Storable<W> + ToPrimitive,
1032    W: Word,
1033    E: Endianness,
1034{
1035    /// Creates a new, empty [`FixedVec`] with a specified bit width.
1036    ///
1037    /// # Errors
1038    ///
1039    /// Returns an [`Error::InvalidParameters`] if `bit_width` is greater than
1040    /// the number of bits in the storage word `W`.
1041    ///
1042    /// # Examples
1043    ///
1044    /// ```
1045    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
1046    ///
1047    /// let vec: UFixedVec<u32> = FixedVec::new(8).unwrap();
1048    /// assert!(vec.is_empty());
1049    /// assert_eq!(vec.bit_width(), 8);
1050    /// ```
1051    pub fn new(bit_width: usize) -> Result<Self, Error> {
1052        if bit_width > <W as traits::Word>::BITS {
1053            return Err(Error::InvalidParameters(format!(
1054                "bit_width ({}) cannot be greater than the word size ({})",
1055                bit_width,
1056                <W as traits::Word>::BITS
1057            )));
1058        }
1059        Ok(unsafe { Self::new_unchecked(Vec::new(), 0, bit_width) })
1060    }
1061
1062    /// Appends an element to the end of the vector.
1063    ///
1064    /// This operation has amortized O(1) complexity.
1065    ///
1066    /// # Panics
1067    ///
1068    /// Panics if the `value` is too large to be represented by the configured
1069    /// `bit_width`.
1070    ///
1071    /// # Examples
1072    ///
1073    /// ```
1074    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
1075    ///
1076    /// let mut vec: UFixedVec<u32> = FixedVec::new(4).unwrap();
1077    /// vec.push(10);
1078    /// vec.push(15);
1079    ///
1080    /// assert_eq!(vec.len(), 2);
1081    /// assert_eq!(vec.get(1), Some(15));
1082    /// ```
1083    #[inline(always)]
1084    pub fn push(&mut self, value: T) {
1085        let value_w = <T as Storable<W>>::into_word(value);
1086
1087        // Check if the value fits within the configured bit width.
1088        if (value_w & !self.mask) != W::ZERO {
1089            panic!(
1090                "Value {:?} does not fit in the configured bit_width of {}",
1091                value_w, self.bit_width
1092            );
1093        }
1094
1095        let bits_per_word = <W as traits::Word>::BITS;
1096        // Grow the underlying buffer if the new element would exceed its bit capacity.
1097        if (self.len + 1) * self.bit_width > self.bits.len() * bits_per_word {
1098            self.bits.push(W::ZERO);
1099        }
1100
1101        // SAFETY: We have ensured the value fits and the buffer has capacity.
1102        unsafe {
1103            self.set_unchecked(self.len, value_w);
1104        }
1105
1106        self.len += 1;
1107    }
1108
1109    /// Removes the last element from the vector and returns it.
1110    ///
1111    /// Returns `None` if the vector is empty.
1112    ///
1113    /// # Examples
1114    ///
1115    /// ```
1116    /// use compressed_intvec::fixed_vec;
1117    ///
1118    /// let mut vec = fixed_vec![1u32, 2, 3];
1119    /// assert_eq!(vec.pop(), Some(3));
1120    /// assert_eq!(vec.len(), 2);
1121    /// ```
1122    pub fn pop(&mut self) -> Option<T> {
1123        if self.is_empty() {
1124            return None;
1125        }
1126        let value = self.get(self.len - 1).unwrap();
1127        self.len -= 1;
1128        Some(value)
1129    }
1130
1131    /// Removes all elements from the vector, leaving the capacity unchanged.
1132    pub fn clear(&mut self) {
1133        self.len = 0;
1134    }
1135
1136    /// Creates a new, empty [`FixedVec`] with a specified bit width and capacity.
1137    ///
1138    /// The vector will be able to hold at least `capacity` elements without
1139    /// reallocating.
1140    ///
1141    /// # Errors
1142    ///
1143    /// Returns an [`Error::InvalidParameters`] if `bit_width` is greater than
1144    /// the number of bits in the storage word `W`.
1145    ///
1146    /// # Examples
1147    ///
1148    /// ```
1149    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
1150    ///
1151    /// let vec: UFixedVec<u32> = FixedVec::with_capacity(5, 1000).unwrap();
1152    /// assert!(vec.capacity() >= 1000);
1153    /// ```
1154    pub fn with_capacity(bit_width: usize, capacity: usize) -> Result<Self, Error> {
1155        if bit_width > <W as traits::Word>::BITS {
1156            return Err(Error::InvalidParameters(format!(
1157                "bit_width ({}) cannot be greater than the word size ({})",
1158                bit_width,
1159                <W as traits::Word>::BITS
1160            )));
1161        }
1162        let bits_per_word = <W as traits::Word>::BITS;
1163        let total_bits = capacity.saturating_mul(bit_width);
1164        let num_words = total_bits.div_ceil(bits_per_word);
1165
1166        let buffer = if capacity == 0 {
1167            Vec::new()
1168        } else {
1169            Vec::with_capacity(num_words + 1) // +1 for padding
1170        };
1171
1172        Ok(unsafe { Self::new_unchecked(buffer, 0, bit_width) })
1173    }
1174
1175    /// Returns the number of elements the vector can hold without reallocating.
1176    pub fn capacity(&self) -> usize {
1177        if self.bit_width == 0 {
1178            return usize::MAX;
1179        }
1180        let word_capacity = self.bits.capacity();
1181        if word_capacity <= 1 {
1182            return 0; // Not enough for data + padding.
1183        }
1184        // Subtract padding words before calculating element capacity.
1185        ((word_capacity - 1) * <W as traits::Word>::BITS) / self.bit_width
1186    }
1187
1188    /// Returns the capacity of the underlying storage in words.
1189    pub fn word_capacity(&self) -> usize {
1190        self.bits.capacity()
1191    }
1192
1193    /// Reserves capacity for at least `additional` more elements to be inserted.
1194    ///
1195    /// # Panics
1196    ///
1197    /// Panics if the new capacity overflows [`usize`].
1198    ///
1199    /// # Examples
1200    ///
1201    /// ```
1202    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
1203    ///
1204    /// let mut vec: UFixedVec<u32> = FixedVec::new(4).unwrap();
1205    /// vec.reserve(100);
1206    /// assert!(vec.capacity() >= 100);
1207    /// ```
1208    pub fn reserve(&mut self, additional: usize) {
1209        let target_element_capacity = self.len.saturating_add(additional);
1210        if self.capacity() >= target_element_capacity {
1211            return;
1212        }
1213        let bits_per_word = <W as Word>::BITS;
1214        let required_total_bits = target_element_capacity.saturating_mul(self.bit_width);
1215        let required_data_words = required_total_bits.div_ceil(bits_per_word);
1216        let required_word_capacity = required_data_words + 1; // +1 for padding
1217
1218        let current_len = self.bits.len();
1219        if self.bits.capacity() < required_word_capacity {
1220            self.bits.reserve(required_word_capacity - current_len);
1221        }
1222    }
1223
1224    /// Resizes the vector so that its length is equal to `new_len`.
1225    ///
1226    /// If `new_len` is greater than the current length, the vector is extended
1227    /// by appending `value`. If `new_len` is less than the current length, the
1228    /// vector is truncated.
1229    ///
1230    /// # Panics
1231    ///
1232    /// Panics if the `value` used for filling does not fit in the configured
1233    /// `bit_width`.
1234    ///
1235    /// # Examples
1236    ///
1237    /// ```
1238    /// use compressed_intvec::fixed::{FixedVec, UFixedVec};
1239    ///
1240    /// let mut vec = UFixedVec::<u32>::new(4).unwrap();
1241    /// vec.push(1);
1242    /// vec.push(2);
1243    ///
1244    /// vec.resize(4, 10);
1245    /// assert_eq!(vec.len(), 4);
1246    /// assert_eq!(vec.get(3), Some(10));
1247    ///
1248    /// vec.resize(1, 0);
1249    /// assert_eq!(vec.len(), 1);
1250    /// assert_eq!(vec.get(0), Some(1));
1251    /// ```
1252    #[inline(always)]
1253    pub fn resize(&mut self, new_len: usize, value: T) {
1254        if new_len > self.len {
1255            let value_w = <T as Storable<W>>::into_word(value);
1256
1257            if (value_w & !self.mask) != W::ZERO {
1258                panic!(
1259                    "Value {:?} does not fit in the configured bit_width of {}",
1260                    value_w, self.bit_width
1261                );
1262            }
1263
1264            let bits_per_word = <W as traits::Word>::BITS;
1265            let required_total_bits = new_len * self.bit_width;
1266            let required_data_words = required_total_bits.div_ceil(bits_per_word);
1267            let required_vec_len = required_data_words.saturating_add(1); // Padding
1268
1269            if self.bits.len() < required_vec_len {
1270                self.bits.resize(required_vec_len, W::ZERO);
1271            }
1272
1273            for i in self.len..new_len {
1274                unsafe {
1275                    self.set_unchecked(i, value_w);
1276                }
1277            }
1278            self.len = new_len;
1279        } else {
1280            self.len = new_len;
1281        }
1282    }
1283
1284    /// Shrinks the capacity of the vector as much as possible.
1285    pub fn shrink_to_fit(&mut self) {
1286        let min_word_len = if self.len == 0 {
1287            0
1288        } else {
1289            let bits_per_word = <W as traits::Word>::BITS;
1290            let required_total_bits = self.len.saturating_mul(self.bit_width);
1291            let required_words = required_total_bits.div_ceil(bits_per_word);
1292            required_words + 1 // +1 for padding
1293        };
1294
1295        if self.bits.len() > min_word_len {
1296            self.bits.truncate(min_word_len);
1297        }
1298        self.bits.shrink_to_fit();
1299    }
1300
1301    /// Removes and returns the element at `index`, shifting all elements after
1302    /// it to the left.
1303    ///
1304    /// This operation is O(n), where n is the number of elements after `index`.
1305    ///
1306    /// # Panics
1307    ///
1308    /// Panics if `index` is out of bounds.
1309    ///
1310    /// # Complexity
1311    ///
1312    /// This operation has a complexity of O(L), where L is the number of bits
1313    /// that need to be shifted. In the worst case (removing the first element),
1314    /// this is proportional to the total number of bits in the vector
1315    /// (`self.len() * self.bit_width()`).
1316    ///
1317    /// # Panics
1318    ///
1319    /// Panics if `index` is out of bounds.
1320    pub fn remove(&mut self, index: usize) -> T {
1321        assert!(index < self.len, "remove: index out of bounds");
1322
1323        let value_to_return = self.get(index).unwrap();
1324
1325        let start_bit = index * self.bit_width;
1326        let end_bit = self.len * self.bit_width;
1327        let total_bits_to_shift = end_bit - (start_bit + self.bit_width);
1328
1329        if total_bits_to_shift > 0 {
1330            self.shift_bits_left(start_bit, self.bit_width, total_bits_to_shift);
1331        }
1332
1333        self.len -= 1;
1334
1335        value_to_return
1336    }
1337
1338    /// Inserts an element at `index`, shifting all elements after it to the right.
1339    ///
1340    /// This operation is O(n), where n is the number of elements after `index`.
1341    ///
1342    /// # Panics
1343    ///
1344    /// Panics if `index` is out of bounds or if the `element` is too large to
1345    /// be represented by the configured `bit_width`.
1346    ///
1347    /// # Complexity
1348    ///
1349    /// This operation has a complexity of O(L), where L is the number of bits
1350    /// that need to be shifted. In the worst case (inserting at the beginning),
1351    /// this is proportional to the total number of bits in the vector
1352    /// (`self.len() * self.bit_width()`).
1353    ///
1354    /// # Panics
1355    ///
1356    /// Panics if `index` is out of bounds or if the `element` is too large to
1357    /// be represented by the configured `bit_width`.
1358    pub fn insert(&mut self, index: usize, element: T) {
1359        assert!(index <= self.len, "insert: index out of bounds");
1360        let value_w = <T as Storable<W>>::into_word(element);
1361        let bits_per_word = <W as Word>::BITS;
1362        let limit = if self.bit_width < bits_per_word {
1363            W::ONE << self.bit_width
1364        } else {
1365            W::max_value()
1366        };
1367        if self.bit_width < bits_per_word && value_w >= limit {
1368            panic!(
1369                "Value {:?} does not fit in the configured bit_width of {}",
1370                value_w, self.bit_width
1371            );
1372        }
1373        self.reserve(1);
1374        let start_shift_bit = index * self.bit_width;
1375        let num_bits_to_move = (self.len - index) * self.bit_width;
1376        if num_bits_to_move > 0 {
1377            self.shift_bits_right(start_shift_bit, self.bit_width, num_bits_to_move);
1378        }
1379        self.len += 1;
1380        unsafe {
1381            self.set_unchecked(index, value_w);
1382        }
1383    }
1384
1385    /// Shifts a range of bits to the left in-place.
1386    fn shift_bits_left(&mut self, start_bit: usize, shift_amount: usize, num_bits_to_move: usize) {
1387        if num_bits_to_move == 0 {
1388            return;
1389        }
1390
1391        let bits_per_word = <W as Word>::BITS;
1392
1393        // Fast path for word-aligned shifts, using `copy_within`.
1394        if shift_amount % bits_per_word == 0 {
1395            let start_write_word = start_bit / bits_per_word;
1396            let start_read_word = (start_bit + shift_amount) / bits_per_word;
1397            let num_words_to_move = num_bits_to_move.div_ceil(bits_per_word);
1398
1399            if start_read_word < self.bits.len() {
1400                let read_end = (start_read_word + num_words_to_move).min(self.bits.len());
1401                self.bits
1402                    .copy_within(start_read_word..read_end, start_write_word);
1403            }
1404            return;
1405        }
1406
1407        // Slow path for unaligned shifts (word-at-a-time).
1408        let shift_rem = shift_amount % bits_per_word;
1409        let inv_shift_rem = bits_per_word - shift_rem;
1410
1411        let start_write_bit = start_bit;
1412        let end_write_bit = start_bit + num_bits_to_move;
1413
1414        let start_write_word = start_write_bit / bits_per_word;
1415        let end_write_word = (end_write_bit - 1) / bits_per_word;
1416
1417        for write_word_idx in start_write_word..=end_write_word {
1418            // Fetch the source data, which may span two source words.
1419            let read_bit = write_word_idx * bits_per_word + shift_rem;
1420            let read_word_idx = read_bit / bits_per_word;
1421
1422            let low_part = self.bits.get(read_word_idx).copied().unwrap_or(W::ZERO) >> shift_rem;
1423            let high_part =
1424                self.bits.get(read_word_idx + 1).copied().unwrap_or(W::ZERO) << inv_shift_rem;
1425
1426            let value_to_write = low_part | high_part;
1427
1428            // Create a mask for the bits we are about to modify.
1429            let mut mask = W::max_value();
1430            if write_word_idx == start_write_word {
1431                mask &= W::max_value() << (start_write_bit % bits_per_word);
1432            }
1433            if write_word_idx == end_write_word {
1434                let end_offset = end_write_bit % bits_per_word;
1435                if end_offset != 0 {
1436                    mask &= (W::ONE << end_offset).wrapping_sub(W::ONE);
1437                }
1438            }
1439
1440            self.bits[write_word_idx] =
1441                (self.bits[write_word_idx] & !mask) | (value_to_write & mask);
1442        }
1443    }
1444
1445    /// Shifts a range of bits to the right in-place.
1446    fn shift_bits_right(&mut self, start_bit: usize, shift_amount: usize, num_bits_to_move: usize) {
1447        if num_bits_to_move == 0 {
1448            return;
1449        }
1450
1451        let bits_per_word = <W as Word>::BITS;
1452
1453        // Ensure the vector has enough capacity and is resized to accommodate the shift.
1454        let required_end_bit = start_bit + shift_amount + num_bits_to_move;
1455        let required_words = required_end_bit.div_ceil(bits_per_word);
1456        let required_vec_len = required_words.saturating_add(1); // +1 for padding
1457        if self.bits.len() < required_vec_len {
1458            self.bits.resize(required_vec_len, W::ZERO);
1459        }
1460
1461        // Fast path for word-aligned shifts.
1462        if shift_amount % bits_per_word == 0 {
1463            let start_read_word = start_bit / bits_per_word;
1464            let start_write_word = (start_bit + shift_amount) / bits_per_word;
1465            let num_words_to_move = num_bits_to_move.div_ceil(bits_per_word);
1466
1467            if start_read_word + num_words_to_move <= self.bits.len() {
1468                self.bits.copy_within(
1469                    start_read_word..start_read_word + num_words_to_move,
1470                    start_write_word,
1471                );
1472            }
1473        } else {
1474            // Slow path for unaligned shifts (iterating from right to left).
1475            let word_shift = shift_amount / bits_per_word;
1476            let shift_rem = shift_amount % bits_per_word;
1477            let inv_shift_rem = bits_per_word - shift_rem;
1478
1479            let start_write_bit = start_bit + shift_amount;
1480            let end_write_bit = start_write_bit + num_bits_to_move;
1481
1482            let start_write_word = start_write_bit / bits_per_word;
1483            let end_write_word = (end_write_bit - 1) / bits_per_word;
1484
1485            for write_word_idx in (start_write_word..=end_write_word).rev() {
1486                let read_word_idx = write_word_idx - word_shift;
1487
1488                // Fetch source data, which may span two words.
1489                let high_part =
1490                    self.bits.get(read_word_idx).copied().unwrap_or(W::ZERO) << shift_rem;
1491                let low_part = if read_word_idx > 0 {
1492                    self.bits.get(read_word_idx - 1).copied().unwrap_or(W::ZERO) >> inv_shift_rem
1493                } else {
1494                    W::ZERO
1495                };
1496                let value_to_write = low_part | high_part;
1497
1498                // Create a mask for the bits we are about to modify.
1499                let mut mask = W::max_value();
1500                if write_word_idx == start_write_word {
1501                    mask &= W::max_value() << (start_write_bit % bits_per_word);
1502                }
1503                if write_word_idx == end_write_word {
1504                    let end_offset = end_write_bit % bits_per_word;
1505                    if end_offset != 0 {
1506                        mask &= (W::ONE << end_offset).wrapping_sub(W::ONE);
1507                    }
1508                }
1509
1510                self.bits[write_word_idx] =
1511                    (self.bits[write_word_idx] & !mask) | (value_to_write & mask);
1512            }
1513        }
1514
1515        // Zero out the vacated bits at the beginning of the shifted region.
1516        let mut clear_bit = start_bit;
1517        let end_clear_bit = start_bit + shift_amount;
1518
1519        while clear_bit < end_clear_bit {
1520            let word_idx = clear_bit / bits_per_word;
1521            let offset = clear_bit % bits_per_word;
1522            let bits_to_clear = (bits_per_word - offset).min(end_clear_bit - clear_bit);
1523
1524            let mask = if bits_to_clear == bits_per_word {
1525                W::max_value()
1526            } else {
1527                ((W::ONE << bits_to_clear).wrapping_sub(W::ONE)) << offset
1528            };
1529
1530            if word_idx < self.bits.len() {
1531                self.bits[word_idx] &= !mask;
1532            }
1533            clear_bit += bits_to_clear;
1534        }
1535    }
1536
1537    /// Removes an element at `index` and returns it, replacing it with the last
1538    /// element of the vector.
1539    ///
1540    /// This operation is O(1) but does not preserve the order of elements.
1541    ///
1542    /// # Panics
1543    ///
1544    /// Panics if `index` is out of bounds.
1545    pub fn swap_remove(&mut self, index: usize) -> T {
1546        assert!(index < self.len, "swap_remove: index out of bounds");
1547
1548        if index == self.len - 1 {
1549            self.pop().unwrap()
1550        } else {
1551            let old_val = unsafe { self.get_unchecked(index) };
1552            let last_val = self.pop().unwrap(); // `pop` already decrements len
1553            self.set(index, last_val);
1554            old_val
1555        }
1556    }
1557
1558    /// Appends an element to the vector, returning an error if the value doesn't fit.
1559    ///
1560    /// # Errors
1561    ///
1562    /// Returns [`Error::ValueTooLarge`] if the `value` cannot be represented
1563    /// by the configured `bit_width`.
1564    pub fn try_push(&mut self, value: T) -> Result<(), Error> {
1565        let value_w = <T as Storable<W>>::into_word(value);
1566        let bits_per_word = <W as traits::Word>::BITS;
1567
1568        let limit = if self.bit_width < bits_per_word {
1569            W::ONE << self.bit_width
1570        } else {
1571            W::max_value()
1572        };
1573
1574        if self.bit_width < bits_per_word && value_w >= limit {
1575            return Err(Error::ValueTooLarge {
1576                value: value_w.to_u128().unwrap(),
1577                index: self.len,
1578                bit_width: self.bit_width,
1579            });
1580        }
1581
1582        self.push(value);
1583        Ok(())
1584    }
1585
1586    /// Extends the vector with the elements from a slice.
1587    ///
1588    /// # Panics
1589    ///
1590    /// Panics if any value in `other` does not fit within the `bit_width`.
1591    pub fn extend_from_slice(&mut self, other: &[T]) {
1592        if other.is_empty() {
1593            return;
1594        }
1595
1596        self.reserve(other.len());
1597
1598        // Pre-validate all values to ensure atomicity.
1599        let bits_per_word = <W as traits::Word>::BITS;
1600        let limit = if self.bit_width < bits_per_word {
1601            W::ONE << self.bit_width
1602        } else {
1603            W::max_value()
1604        };
1605        if self.bit_width < bits_per_word {
1606            for (i, &value) in other.iter().enumerate() {
1607                let value_w = <T as Storable<W>>::into_word(value);
1608                if value_w >= limit {
1609                    panic!(
1610                        "Value at index {} of slice ({:?}) does not fit in the configured bit_width of {}",
1611                        i, value_w, self.bit_width
1612                    );
1613                }
1614            }
1615        }
1616
1617        let old_len = self.len;
1618        let new_len = old_len + other.len();
1619
1620        // Ensure the underlying Vec has enough initialized words to write into.
1621        let required_total_bits = new_len * self.bit_width;
1622        let required_data_words = required_total_bits.div_ceil(bits_per_word);
1623        let required_vec_len = required_data_words.saturating_add(1); // Padding
1624        if self.bits.len() < required_vec_len {
1625            self.bits.resize(required_vec_len, W::ZERO);
1626        }
1627
1628        // Write the new values.
1629        for (i, &value) in other.iter().enumerate() {
1630            // SAFETY: We have reserved, resized, and validated the data.
1631            unsafe {
1632                self.set_unchecked(old_len + i, <T as Storable<W>>::into_word(value));
1633            }
1634        }
1635
1636        self.len = new_len;
1637    }
1638}
1639
1640// Mutable in-place operations.
1641impl<T, W, E, B> FixedVec<T, W, E, B>
1642where
1643    T: Storable<W>,
1644    W: Word,
1645    E: Endianness,
1646    B: AsRef<[W]> + AsMut<[W]>,
1647{
1648    /// Returns a mutable proxy for an element at `index`.
1649    ///
1650    /// This allows for syntax like `*vec.at_mut(i).unwrap() = new_value;`.
1651    ///
1652    /// Returns `None` if the index is out of bounds.
1653    pub fn at_mut(&mut self, index: usize) -> Option<MutProxy<'_, T, W, E, B>> {
1654        if index >= self.len {
1655            return None;
1656        }
1657        Some(MutProxy::new(self, index))
1658    }
1659
1660    /// Returns a mutable slice of the underlying storage words.
1661    ///
1662    /// # Safety
1663    ///
1664    /// Modifying the returned slice is logically unsafe. Any change to the bits
1665    /// can violate the invariants of the [`FixedVec`], leading to panics or
1666    /// incorrect results on subsequent method calls.
1667    pub unsafe fn as_mut_limbs(&mut self) -> &mut [W] {
1668        self.bits.as_mut()
1669    }
1670
1671    /// Sets the value of the element at `index`.
1672    ///
1673    /// # Panics
1674    ///
1675    /// Panics if `index` is out of bounds or if `value` is too large to be
1676    /// represented by the configured `bit_width`.
1677    ///
1678    /// # Examples
1679    ///
1680    /// ```
1681    /// use compressed_intvec::fixed::{FixedVec, UFixedVec, BitWidth};
1682    ///
1683    /// let data: &[u32] = &[10, 20, 30];
1684    /// let mut vec: UFixedVec<u32> = FixedVec::builder().bit_width(BitWidth::Explicit(7)).build(data).unwrap();
1685    ///
1686    /// vec.set(1, 99);
1687    /// assert_eq!(vec.get(1), Some(99));
1688    /// ```
1689    pub fn set(&mut self, index: usize, value: T) {
1690        assert!(
1691            index < self.len,
1692            "Index out of bounds: expected index < {}, got {}",
1693            self.len,
1694            index
1695        );
1696
1697        let value_w = <T as Storable<W>>::into_word(value);
1698        let bits_per_word = <W as traits::Word>::BITS;
1699
1700        let limit = if self.bit_width < bits_per_word {
1701            W::ONE << self.bit_width
1702        } else {
1703            W::max_value()
1704        };
1705
1706        if self.bit_width < bits_per_word && value_w >= limit {
1707            panic!(
1708                "Value {:?} does not fit in the configured bit_width of {}",
1709                value_w, self.bit_width
1710            );
1711        }
1712
1713        unsafe { self.set_unchecked(index, value_w) };
1714    }
1715
1716    /// Sets the value of the element at `index` without bounds or value checking.
1717    ///
1718    /// # Safety
1719    ///
1720    /// The caller must ensure that `index` is within bounds and that `value_w`
1721    /// fits within the configured `bit_width`. Failure to do so will result in
1722    /// data corruption or a panic.
1723    #[inline(always)]
1724    pub unsafe fn set_unchecked(&mut self, index: usize, value_w: W) {
1725        let bits_per_word = <W as traits::Word>::BITS;
1726        if self.bit_width == bits_per_word {
1727            *self.bits.as_mut().get_unchecked_mut(index) = if E::IS_LITTLE {
1728                value_w
1729            } else {
1730                value_w.to_be()
1731            };
1732            return;
1733        }
1734        
1735        let bit_pos = index * self.bit_width;
1736        let word_index = bit_pos / bits_per_word;
1737        let bit_offset = bit_pos % bits_per_word;
1738
1739        let limbs = self.bits.as_mut();
1740
1741        if E::IS_LITTLE {
1742            // Fast path: the value fits entirely within a single word.
1743            if bit_offset + self.bit_width <= bits_per_word {
1744                let mut word = *limbs.get_unchecked(word_index);
1745                // Clear the target bits and then OR the new value.
1746                word &= !(self.mask << bit_offset);
1747                word |= value_w << bit_offset;
1748                *limbs.get_unchecked_mut(word_index) = word;
1749            } else {
1750                let remaining_bits_in_first_word = bits_per_word - bit_offset;
1751                let (left, right) = limbs.split_at_mut_unchecked(word_index + 1);
1752                let mut low_word_val = *left.get_unchecked(word_index);
1753                let low_mask = (<W as num_traits::NumCast>::from(1u8).unwrap() << bit_offset)
1754                    .wrapping_sub(<W as num_traits::NumCast>::from(1u8).unwrap());
1755                low_word_val &= low_mask;
1756                low_word_val |= value_w << bit_offset;
1757                *left.get_unchecked_mut(word_index) = low_word_val;
1758
1759                let mut high_word_val = *right.get_unchecked(0);
1760                high_word_val &= !(self.mask >> remaining_bits_in_first_word);
1761                high_word_val |= value_w >> remaining_bits_in_first_word;
1762                *right.get_unchecked_mut(0) = high_word_val;
1763            }
1764        } else {
1765            // Big-Endian set logic.
1766            if bit_offset + self.bit_width <= bits_per_word {
1767                let shift = bits_per_word - self.bit_width - bit_offset;
1768                let mask = self.mask << shift;
1769                let word = limbs.get_unchecked_mut(word_index);
1770                *word &= !mask.to_be();
1771                *word |= (value_w << shift).to_be();
1772            } else {
1773                let (left, right) = limbs.split_at_mut_unchecked(word_index + 1);
1774                let high_word = left.get_unchecked_mut(word_index);
1775                let low_word = right.get_unchecked_mut(0);
1776
1777                let bits_in_first = bits_per_word - bit_offset;
1778                let bits_in_second = self.bit_width - bits_in_first;
1779
1780                let high_mask =
1781                    (self.mask >> bits_in_second) << (bits_per_word - bits_in_first - bit_offset);
1782                let high_value = value_w >> bits_in_second;
1783                *high_word &= !high_mask.to_be();
1784                *high_word |= (high_value << (bits_per_word - bits_in_first - bit_offset)).to_be();
1785
1786                let low_mask = self.mask << (bits_per_word - bits_in_second);
1787                let low_value = value_w << (bits_per_word - bits_in_second);
1788                *low_word &= !low_mask.to_be();
1789                *low_word |= low_value.to_be();
1790            }
1791        }
1792    }
1793
1794    /// Sets the value of an element, returning an error if the value doesn't fit.
1795    ///
1796    /// # Errors
1797    ///
1798    /// Returns [`Error::ValueTooLarge`] if the `value` cannot be represented
1799    /// by the configured `bit_width`.
1800    ///
1801    /// # Panics
1802    ///
1803    /// Panics if `index` is out of bounds.
1804    pub fn try_set(&mut self, index: usize, value: T) -> Result<(), Error> {
1805        assert!(index < self.len, "try_set: index out of bounds");
1806
1807        let value_w = <T as Storable<W>>::into_word(value);
1808        let bits_per_word = <W as traits::Word>::BITS;
1809
1810        let limit = if self.bit_width < bits_per_word {
1811            W::ONE << self.bit_width
1812        } else {
1813            W::max_value()
1814        };
1815
1816        if self.bit_width < bits_per_word && value_w >= limit {
1817            return Err(Error::ValueTooLarge {
1818                value: value_w.to_u128().unwrap(),
1819                index,
1820                bit_width: self.bit_width,
1821            });
1822        }
1823
1824        unsafe { self.set_unchecked(index, value_w) };
1825        Ok(())
1826    }
1827
1828    /// Returns an iterator over non-overlapping, mutable chunks of the vector.
1829    ///
1830    /// # Panics
1831    ///
1832    /// Panics if `chunk_size` is 0.
1833    pub fn chunks_mut(&mut self, chunk_size: usize) -> iter_mut::ChunksMut<'_, T, W, E, B> {
1834        iter_mut::ChunksMut::new(self, chunk_size)
1835    }
1836
1837    /// Returns an unchecked mutable iterator over the elements of the vector.
1838    ///
1839    /// # Safety
1840    ///
1841    /// The caller must ensure that the iterator is not advanced beyond the
1842    /// vector's length.
1843    pub unsafe fn iter_mut_unchecked(&mut self) -> iter_mut::IterMutUnchecked<'_, T, W, E, B> {
1844        iter_mut::IterMutUnchecked::new(self)
1845    }
1846
1847    /// Applies a function to all elements in place, without checking if the
1848    /// returned values fit within the `bit_width`.
1849    ///
1850    /// # Safety
1851    ///
1852    /// The caller must ensure that the function `f` always returns a value
1853    /// that can be represented by `self.bit_width()` bits. Returning a value
1854    /// that is too large will result in data corruption.
1855    pub unsafe fn map_in_place_unchecked<F>(&mut self, mut f: F)
1856    where
1857        F: FnMut(T) -> T,
1858    {
1859        if E::IS_LITTLE {
1860            // This path operates on words directly for efficiency.
1861            let mut word_op = |word: W| -> W {
1862                let val_t = <T as Storable<W>>::from_word(word);
1863                let new_val_t = f(val_t);
1864                <T as Storable<W>>::into_word(new_val_t)
1865            };
1866            self.map_in_place_generic_word_op(&mut word_op);
1867        } else {
1868            // Fallback for BE, which is more complex to optimize at the word level.
1869            for i in 0..self.len {
1870                let old_val_t = self.get_unchecked(i);
1871                let new_val_t = f(old_val_t);
1872                self.set_unchecked(i, <T as Storable<W>>::into_word(new_val_t));
1873            }
1874        }
1875    }
1876
1877    /// Internal worker for `map_in_place_unchecked`, operating on `W`.
1878    unsafe fn map_in_place_generic_word_op<FW>(&mut self, f_w: &mut FW)
1879    where
1880        FW: FnMut(W) -> W,
1881    {
1882        let bit_width = self.bit_width;
1883        if self.len == 0 || bit_width == 0 {
1884            return;
1885        }
1886
1887        let bits_per_word = <W as Word>::BITS;
1888
1889        // Path for power-of-two bit widths that align with word boundaries.
1890        if bit_width.is_power_of_two() && bits_per_word % bit_width == 0 {
1891            let elems_per_word = bits_per_word / bit_width;
1892            let mask = self.mask;
1893            let num_full_words = self.len / elems_per_word;
1894
1895            for word_idx in 0..num_full_words {
1896                let old_word = *self.bits.as_ref().get_unchecked(word_idx);
1897                let mut new_word = W::ZERO;
1898                for i in 0..elems_per_word {
1899                    let shift = i * bit_width;
1900                    let old_val_w = (old_word >> shift) & mask;
1901                    new_word |= f_w(old_val_w) << shift;
1902                }
1903                *self.bits.as_mut().get_unchecked_mut(word_idx) = new_word;
1904            }
1905            // Process remaining elements individually.
1906            let start_idx = num_full_words * elems_per_word;
1907            for i in start_idx..self.len {
1908                let old_val_t = self.get(i).unwrap();
1909                let old_val_w = <T as Storable<W>>::into_word(old_val_t);
1910                self.set_unchecked(i, f_w(old_val_w));
1911            }
1912            return;
1913        }
1914
1915        // Generic path for non-power-of-two bit widths.
1916        let limbs = self.bits.as_mut();
1917        let num_words = (self.len * bit_width).div_ceil(bits_per_word);
1918        let last_word_idx = num_words.saturating_sub(1);
1919
1920        let mut write_buffer = W::ZERO;
1921        let mut read_buffer = *limbs.get_unchecked(0);
1922        let mut global_bit_offset = 0;
1923
1924        for word_idx in 0..last_word_idx {
1925            let lower_word_boundary = word_idx * bits_per_word;
1926            let upper_word_boundary = lower_word_boundary + bits_per_word;
1927
1928            while global_bit_offset + bit_width <= upper_word_boundary {
1929                let offset_in_word = global_bit_offset - lower_word_boundary;
1930                let element = (read_buffer >> offset_in_word) & self.mask;
1931                write_buffer |= f_w(element) << offset_in_word;
1932                global_bit_offset += bit_width;
1933            }
1934
1935            let next_word = *limbs.get_unchecked(word_idx + 1);
1936            let mut new_write_buffer = W::ZERO;
1937
1938            if upper_word_boundary != global_bit_offset {
1939                let elem_idx = global_bit_offset / bit_width;
1940                if elem_idx >= self.len {
1941                    *limbs.get_unchecked_mut(word_idx) = write_buffer;
1942                    return;
1943                }
1944
1945                let remainder_in_word = upper_word_boundary - global_bit_offset;
1946                let offset_in_word = global_bit_offset - lower_word_boundary;
1947
1948                let element = ((read_buffer >> offset_in_word) | (next_word << remainder_in_word))
1949                    & self.mask;
1950                let new_element = f_w(element);
1951
1952                write_buffer |= new_element << offset_in_word;
1953                new_write_buffer = new_element >> remainder_in_word;
1954
1955                global_bit_offset += bit_width;
1956            }
1957
1958            *limbs.get_unchecked_mut(word_idx) = write_buffer;
1959
1960            read_buffer = next_word;
1961            write_buffer = new_write_buffer;
1962        }
1963
1964        let lower_word_boundary = last_word_idx * bits_per_word;
1965
1966        while global_bit_offset < self.len * bit_width {
1967            let offset_in_word = global_bit_offset - lower_word_boundary;
1968            let element = (read_buffer >> offset_in_word) & self.mask;
1969            write_buffer |= f_w(element) << offset_in_word;
1970            global_bit_offset += bit_width;
1971        }
1972
1973        *limbs.get_unchecked_mut(last_word_idx) = write_buffer;
1974    }
1975
1976    /// Applies a function to all elements in the vector, modifying them in-place.
1977    ///
1978    /// # Panics
1979    ///
1980    /// Panics if the function `f` returns a value that does not fit within the
1981    /// configured `bit_width`.
1982    ///
1983    /// # Examples
1984    ///
1985    /// ```
1986    /// use compressed_intvec::fixed::{FixedVec, BitWidth, UFixedVec};
1987    ///
1988    /// // Values up to 9*2=18, requires 5 bits. We must build with enough space.
1989    /// let initial_data: Vec<u32> = (0..10).collect();
1990    /// let mut vec: UFixedVec<u32> = FixedVec::builder()
1991    ///     .bit_width(BitWidth::Explicit(5))
1992    ///     .build(&initial_data)
1993    ///     .unwrap();
1994    ///
1995    /// vec.map_in_place(|x| x * 2);
1996    ///
1997    /// for i in 0..vec.len() {
1998    ///     assert_eq!(vec.get(i), Some(i as u32 * 2));
1999    /// }
2000    /// ```
2001    pub fn map_in_place<F>(&mut self, mut f: F)
2002    where
2003        F: FnMut(T) -> T,
2004    {
2005        let bit_width = self.bit_width;
2006        let limit = if bit_width < <W as Word>::BITS {
2007            W::ONE << bit_width
2008        } else {
2009            W::max_value()
2010        };
2011
2012        let safe_f = |value: T| {
2013            let new_value = f(value);
2014            let new_value_w = <T as Storable<W>>::into_word(new_value);
2015            if bit_width < <W as Word>::BITS && new_value_w >= limit {
2016                panic!(
2017                    "map_in_place: returned value {new_value_w:?} does not fit in bit_width {bit_width}"
2018                );
2019            }
2020            new_value
2021        };
2022
2023        // SAFETY: The `safe_f` wrapper ensures that any value passed to the
2024        // underlying unsafe function is valid for the vector's bit_width.
2025        unsafe {
2026            self.map_in_place_unchecked(safe_f);
2027        }
2028    }
2029
2030    /// Replaces the element at `index` with a new `value`, returning the old value.
2031    ///
2032    /// # Panics
2033    ///
2034    /// Panics if `index` is out of bounds or if `value` does not fit within
2035    /// the configured `bit_width`.
2036    pub fn replace(&mut self, index: usize, value: T) -> T {
2037        assert!(index < self.len, "replace: index out of bounds");
2038
2039        let old_value = unsafe { self.get_unchecked(index) };
2040        self.set(index, value);
2041        old_value
2042    }
2043
2044    /// Swaps the elements at indices `a` and `b`.
2045    ///
2046    /// # Panics
2047    ///
2048    /// Panics if `a` or `b` are out of bounds.
2049    pub fn swap(&mut self, a: usize, b: usize) {
2050        assert!(a < self.len, "swap: index a out of bounds");
2051        assert!(b < self.len, "swap: index b out of bounds");
2052
2053        if a == b {
2054            return;
2055        }
2056
2057        unsafe {
2058            let val_a = self.get_unchecked(a);
2059            let val_b = self.get_unchecked(b);
2060            self.set_unchecked(a, <T as Storable<W>>::into_word(val_b));
2061            self.set_unchecked(b, <T as Storable<W>>::into_word(val_a));
2062        }
2063    }
2064
2065    /// Returns a mutable proxy to the first element, or `None` if empty.
2066    pub fn first_mut(&mut self) -> Option<MutProxy<'_, T, W, E, B>> {
2067        if self.is_empty() {
2068            None
2069        } else {
2070            self.at_mut(0)
2071        }
2072    }
2073
2074    /// Returns a mutable proxy to the last element, or `None` if empty.
2075    pub fn last_mut(&mut self) -> Option<MutProxy<'_, T, W, E, B>> {
2076        if self.is_empty() {
2077            None
2078        } else {
2079            let len = self.len();
2080            self.at_mut(len - 1)
2081        }
2082    }
2083
2084    /// Returns the first element of the vector, or `None` if empty.
2085    pub fn first(&self) -> Option<T> {
2086        if self.is_empty() {
2087            None
2088        } else {
2089            Some(unsafe { self.get_unchecked(0) })
2090        }
2091    }
2092
2093    /// Returns the last element of the vector, or `None` if empty.
2094    pub fn last(&self) -> Option<T> {
2095        if self.is_empty() {
2096            None
2097        } else {
2098            let len = self.len();
2099            Some(unsafe { self.get_unchecked(len - 1) })
2100        }
2101    }
2102
2103    /// Splits the vector into two mutable slices at `mid`.
2104    ///
2105    /// # Panics
2106    ///
2107    /// Panics if `mid > len`.
2108    pub fn split_at_mut(
2109        &mut self,
2110        mid: usize,
2111    ) -> (
2112        slice::FixedVecSlice<&mut Self>,
2113        slice::FixedVecSlice<&mut Self>,
2114    ) {
2115        assert!(mid <= self.len, "mid > len in split_at_mut");
2116        // SAFETY: The two slices are guaranteed not to overlap.
2117        unsafe {
2118            let ptr = self as *mut Self;
2119            let left = slice::FixedVecSlice::new(&mut *ptr, 0..mid);
2120            let right = slice::FixedVecSlice::new(&mut *ptr, mid..self.len());
2121            (left, right)
2122        }
2123    }
2124
2125    /// Returns a mutable iterator over the elements of the vector.
2126    pub fn iter_mut(&mut self) -> iter_mut::IterMut<'_, T, W, E, B> {
2127        iter_mut::IterMut::new(self)
2128    }
2129
2130    /// Rotates the elements of the vector in-place such that the element at `mid`
2131    /// becomes the first element.
2132    ///
2133    /// # Panics
2134    ///
2135    /// Panics if `mid > len`.
2136    pub fn rotate_left(&mut self, mid: usize) {
2137        assert!(mid <= self.len, "mid > len in rotate_left");
2138        if self.is_empty() || mid == 0 || mid == self.len {
2139            return;
2140        }
2141        // A simple, correct implementation.
2142        let mut temp = Vec::with_capacity(mid);
2143        for i in 0..mid {
2144            temp.push(unsafe { self.get_unchecked(i) });
2145        }
2146        for i in mid..self.len {
2147            let val = unsafe { self.get_unchecked(i) };
2148            unsafe { self.set_unchecked(i - mid, <T as Storable<W>>::into_word(val)) };
2149        }
2150        for (i, val) in temp.into_iter().enumerate() {
2151            unsafe { self.set_unchecked(self.len - mid + i, <T as Storable<W>>::into_word(val)) };
2152        }
2153    }
2154
2155    /// Rotates the elements of the vector in-place such that the element at
2156    /// `len - k` becomes the first element.
2157    ///
2158    /// # Panics
2159    ///
2160    /// Panics if `k > len`.
2161    pub fn rotate_right(&mut self, k: usize) {
2162        assert!(k <= self.len, "k > len in rotate_right");
2163        if self.is_empty() || k == 0 || k == self.len {
2164            return;
2165        }
2166        self.rotate_left(self.len - k);
2167    }
2168
2169    /// Fills the vector with the given value.
2170    ///
2171    /// # Panics
2172    ///
2173    /// Panics if `value` does not fit in the configured `bit_width`.
2174    pub fn fill(&mut self, value: T) {
2175        let value_w = <T as Storable<W>>::into_word(value);
2176        let bits_per_word = <W as traits::Word>::BITS;
2177        let limit = if self.bit_width < bits_per_word {
2178            W::ONE << self.bit_width
2179        } else {
2180            W::max_value()
2181        };
2182        if self.bit_width < bits_per_word && value_w >= limit {
2183            panic!(
2184                "Value {:?} does not fit in the configured bit_width of {}",
2185                value_w, self.bit_width
2186            );
2187        }
2188
2189        for i in 0..self.len() {
2190            unsafe { self.set_unchecked(i, value_w) };
2191        }
2192    }
2193
2194    /// Fills the vector with values returned by a closure.
2195    ///
2196    /// # Panics
2197    ///
2198    /// Panics if the closure returns a value that does not fit in the configured
2199    /// `bit_width`.
2200    pub fn fill_with<F>(&mut self, mut f: F)
2201    where
2202        F: FnMut() -> T,
2203    {
2204        let bits_per_word = <W as traits::Word>::BITS;
2205        let limit = if self.bit_width < bits_per_word {
2206            W::ONE << self.bit_width
2207        } else {
2208            W::max_value()
2209        };
2210
2211        for i in 0..self.len() {
2212            let value = f();
2213            let value_w = <T as Storable<W>>::into_word(value);
2214            if self.bit_width < bits_per_word && value_w >= limit {
2215                panic!(
2216                    "Value {:?} returned by closure does not fit in bit_width {}",
2217                    value_w, self.bit_width
2218                );
2219            }
2220            unsafe { self.set_unchecked(i, value_w) };
2221        }
2222    }
2223
2224    /// Copies a sequence of elements from a source [`FixedVec`] into this one.
2225    ///
2226    /// # Panics
2227    ///
2228    /// Panics if the source and destination vectors do not have the same `bit_width`,
2229    /// or if the source or destination ranges are out of bounds.
2230    pub fn copy_from_slice(
2231        &mut self,
2232        src: &Self,
2233        src_range: std::ops::Range<usize>,
2234        dest_index: usize,
2235    ) {
2236        assert_eq!(
2237            self.bit_width, src.bit_width,
2238            "bit_width mismatch in copy_from_slice"
2239        );
2240        assert!(src_range.start <= src_range.end, "source range start > end");
2241        assert!(src_range.end <= src.len(), "source range out of bounds");
2242        let len = src_range.len();
2243        assert!(
2244            dest_index + len <= self.len(),
2245            "destination range out of bounds"
2246        );
2247
2248        if len == 0 {
2249            return;
2250        }
2251
2252        // Fast path: if bit alignments are the same, we can do word-level copies.
2253        let bit_width = self.bit_width;
2254        let bits_per_word = <W as Word>::BITS;
2255        let src_bit_offset = (src_range.start * bit_width) % bits_per_word;
2256        let dest_bit_offset = (dest_index * bit_width) % bits_per_word;
2257
2258        if src_bit_offset == dest_bit_offset {
2259            let src_word_start = (src_range.start * bit_width) / bits_per_word;
2260            let dest_word_start = (dest_index * bit_width) / bits_per_word;
2261            let total_bits_to_copy = len * bit_width;
2262            let num_words_to_copy = total_bits_to_copy.div_ceil(bits_per_word);
2263
2264            let src_words = &src.bits.as_ref()[src_word_start..src_word_start + num_words_to_copy];
2265            let dest_words =
2266                &mut self.bits.as_mut()[dest_word_start..dest_word_start + num_words_to_copy];
2267
2268            // If the last word is not fully copied, we need to mask it.
2269            let residual_bits = total_bits_to_copy % bits_per_word;
2270            if residual_bits == 0 {
2271                dest_words.copy_from_slice(src_words);
2272            } else {
2273                if num_words_to_copy > 1 {
2274                    dest_words[..num_words_to_copy - 1]
2275                        .copy_from_slice(&src_words[..num_words_to_copy - 1]);
2276                }
2277                let last_word_mask = (W::ONE << residual_bits).wrapping_sub(W::ONE);
2278                let dest_last_word = &mut dest_words[num_words_to_copy - 1];
2279                let src_last_word = &src_words[num_words_to_copy - 1];
2280                *dest_last_word =
2281                    (*dest_last_word & !last_word_mask) | (*src_last_word & last_word_mask);
2282            }
2283        } else {
2284            // Slow path: copy element by element if alignments differ.
2285            if dest_index > src_range.start && dest_index < src_range.end {
2286                // Copy backwards if ranges overlap and dest is after src.
2287                for i in (0..len).rev() {
2288                    let val = unsafe { src.get_unchecked(src_range.start + i) };
2289                    unsafe {
2290                        self.set_unchecked(dest_index + i, <T as Storable<W>>::into_word(val))
2291                    };
2292                }
2293            } else {
2294                for i in 0..len {
2295                    let val = unsafe { src.get_unchecked(src_range.start + i) };
2296                    unsafe {
2297                        self.set_unchecked(dest_index + i, <T as Storable<W>>::into_word(val))
2298                    };
2299                }
2300            }
2301        }
2302    }
2303}
2304
2305impl<T, W, E, B, B2> PartialEq<FixedVec<T, W, E, B2>> for FixedVec<T, W, E, B>
2306where
2307    T: Storable<W> + PartialEq,
2308    W: Word,
2309    E: Endianness,
2310    B: AsRef<[W]>,
2311    B2: AsRef<[W]>,
2312{
2313    /// Checks for equality between two [`FixedVec`] instances.
2314    ///
2315    /// It first checks `len` and `bit_width`, then the underlying storage.
2316    fn eq(&self, other: &FixedVec<T, W, E, B2>) -> bool {
2317        if self.len() != other.len() || self.bit_width() != other.bit_width() {
2318            return false;
2319        }
2320        self.as_limbs() == other.as_limbs()
2321    }
2322}
2323
2324/// Implements `PartialEq` for comparing a [`FixedVec`] with a standard slice.
2325impl<T, W, E, B, T2> PartialEq<&[T2]> for FixedVec<T, W, E, B>
2326where
2327    T: Storable<W> + PartialEq<T2>,
2328    W: Word,
2329    E: Endianness,
2330    B: AsRef<[W]>,
2331    T2: Clone,
2332{
2333    fn eq(&self, other: &&[T2]) -> bool {
2334        if self.len() != other.len() {
2335            return false;
2336        }
2337        self.iter().zip(other.iter()).all(|(a, b)| a == *b)
2338    }
2339}
2340
2341impl<T, W, E> Extend<T> for FixedVec<T, W, E, Vec<W>>
2342where
2343    T: Storable<W> + ToPrimitive,
2344    W: Word,
2345    E: Endianness,
2346{
2347    /// Extends the vector with the contents of an iterator.
2348    ///
2349    /// # Panics
2350    ///
2351    /// Panics if any value from the iterator does not fit within the
2352    /// configured `bit_width`.
2353    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
2354        let iter = iter.into_iter();
2355        let (lower_bound, _) = iter.size_hint();
2356        self.reserve(lower_bound);
2357        for item in iter {
2358            self.push(item);
2359        }
2360    }
2361}
2362
2363impl<T, W, E> From<FixedVec<T, W, E, Vec<W>>> for FixedVec<T, W, E, Box<[W]>>
2364where
2365    T: Storable<W>,
2366    W: Word,
2367    E: Endianness,
2368{
2369    /// Converts a `Vec`-backed [`FixedVec`] into a `Box<[]>`-backed [`FixedVec`].
2370    fn from(vec: FixedVec<T, W, E, Vec<W>>) -> Self {
2371        unsafe { Self::new_unchecked(vec.bits.into_boxed_slice(), vec.len, vec.bit_width) }
2372    }
2373}
2374
2375impl<T, W, E> From<FixedVec<T, W, E, Box<[W]>>> for FixedVec<T, W, E, Vec<W>>
2376where
2377    T: Storable<W>,
2378    W: Word,
2379    E: Endianness,
2380{
2381    /// Converts a `Box<[]>`-backed [`FixedVec`] into a `Vec`-backed [`FixedVec`].
2382    fn from(vec: FixedVec<T, W, E, Box<[W]>>) -> Self {
2383        unsafe { Self::new_unchecked(vec.bits.into_vec(), vec.len, vec.bit_width) }
2384    }
2385}
2386
2387impl<'a, T> TryFrom<&'a [T]> for FixedVec<T, <T as DefaultParams>::W, <T as DefaultParams>::E>
2388where
2389    T: Storable<<T as DefaultParams>::W> + DefaultParams,
2390    <T as DefaultParams>::W: Word,
2391    <T as DefaultParams>::E: Endianness,
2392    dsi_bitstream::impls::BufBitWriter<
2393        <T as DefaultParams>::E,
2394        dsi_bitstream::impls::MemWordWriterVec<
2395            <T as DefaultParams>::W,
2396            Vec<<T as DefaultParams>::W>,
2397        >,
2398    >: dsi_bitstream::prelude::BitWrite<<T as DefaultParams>::E, Error = std::convert::Infallible>,
2399{
2400    type Error = Error;
2401
2402    /// Creates a [`FixedVec`] from a slice using [`BitWidth::Minimal`] and default parameters.
2403    ///
2404    /// This is a convenience method equivalent to `FixedVec::builder().build(slice)`.
2405    /// It uses the default [`Word`] ([`usize`]) and [`Endianness`] ([`LE`]) associated with the element type `T`.
2406    ///
2407    /// # Examples
2408    ///
2409    /// ```
2410    /// use compressed_intvec::fixed::{UFixedVec, SFixedVec};
2411    /// use std::convert::TryFrom;
2412    ///
2413    /// // For unsigned types
2414    /// let data_u: &[u32] = &[10, 20, 30];
2415    /// let vec_u = UFixedVec::<u32>::try_from(data_u).unwrap();
2416    /// assert_eq!(vec_u.bit_width(), 5);
2417    ///
2418    /// // For signed types
2419    /// let data_s: &[i16] = &[-10, 0, 10];
2420    /// let vec_s = SFixedVec::<i16>::try_from(data_s).unwrap();
2421    /// assert_eq!(vec_s.bit_width(), 5);
2422    /// ```
2423    fn try_from(slice: &'a [T]) -> Result<Self, Self::Error> {
2424        Self::builder().bit_width(BitWidth::Minimal).build(slice)
2425    }
2426}