sux/traits/
bit_field_slice.rs

1/*
2 * SPDX-FileCopyrightText: 2023 Inria
3 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
4 *
5 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
6 */
7
8//! Traits for slices of bit fields of constant width.
9//!
10//! Slices of bit fields are accessed with a logic similar to slices, but when
11//! indexed with [`get`](BitFieldSlice::get) return an owned value of a [fixed
12//! bit width](BitFieldSliceCore::bit_width). The associated implementation is
13//! [`BitFieldVec`](crate::bits::bit_field_vec::BitFieldVec).
14//!
15//! Implementing the
16//! [`Index`](core::ops::Index)/[`IndexMut`](core::ops::IndexMut) traits would
17//! be more natural and practical, but in certain cases it is impossible: in our
18//! main use case, [`BitFieldVec`](crate::bits::bit_field_vec::BitFieldVec), we
19//! cannot implement [`Index`](core::ops::Index) because there is no way to
20//! return a reference to a bit segment.
21//!
22//! There are three end-user traits: [`BitFieldSlice`], [`BitFieldSliceMut`] and
23//! [`AtomicBitFieldSlice`]. The trait [`BitFieldSliceCore`] contains the common
24//! methods, and in particular [`BitFieldSliceCore::bit_width`], which returns
25//!  the bit width the values stored in the slice. All stored values must fit
26//!  within this bit width.
27//!
28//! All the traits depends on a type parameter `W` that must implement [`Word`],
29//! and which default to `usize`, but any type satisfying the [`Word`] trait can
30//! be used, with the restriction that the bit width of the slice can be at most
31//! the bit width of `W` as defined by [`AsBytes::BITS`]. Additionally, to
32//! implement [`AtomicBitFieldSlice`], `W` must implement [`IntoAtomic`]. The
33//! methods of all traits accept and return values of type `W`.
34//!
35//! If you need to iterate over a [`BitFieldSlice`], you can use
36//! [`BitFieldSliceIterator`].
37//!
38//! Implementations must return always zero on a [`BitFieldSlice::get`] when the
39//! bit width is zero. The behavior of a [`BitFieldSliceMut::set`] in the same
40//! context is not defined.
41//!
42//! It is suggested that types implementing [`BitFieldSlice`] implement on a
43//! reference [`IntoIterator`] with item `W` using [`BitFieldSliceIterator`] as
44//! helper.
45//!
46//! We provide implementations for vectors and slices of all primitive atomic
47//! and non-atomic unsigned integer types that view their elements as values
48//! with a bit width equal to that of the type.
49//!
50//! # Simpler methods for atomic slices
51//!
52//! [`AtomicBitFieldSlice`] has rather cumbersome method names. There is however
53//! a trait [`AtomicHelper`] that can be imported that will add to
54//! [`AtomicBitFieldSlice`] equivalent methods without the `_atomic` infix. You
55//! should be however careful to not mix [`AtomicHelper`] and [`BitFieldSlice`]
56//! or a number of ambiguities in trait resolution will arise. In particular, if
57//! you plan to use [`AtomicHelper`], we suggest that you do not import the
58//! prelude.
59//! ```rust
60//! use sux::traits::bit_field_slice::{AtomicBitFieldSlice,AtomicHelper};
61//! use std::sync::atomic::Ordering;
62//!
63//! let slice = sux::bits::AtomicBitFieldVec::<usize>::new(3, 3);
64//! slice.set(0, 1, Ordering::Relaxed);
65//! assert_eq!(slice.get(0, Ordering::Relaxed), 1);
66//! ```
67
68#![allow(clippy::result_unit_err)]
69use common_traits::*;
70use core::sync::atomic::*;
71use mem_dbg::{MemDbg, MemSize};
72#[cfg(feature = "rayon")]
73use rayon::iter::{
74    IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator,
75};
76use std::marker::PhantomData;
77
78/// A derived trait that the types used as a parameter for [`BitFieldSlice`] must satisfy.
79/// To be usable in an [`AtomicBitFieldSlice`], the type must also implement [`IntoAtomic`].
80pub trait Word: UnsignedInt + FiniteRangeNumber + AsBytes {}
81impl<W: UnsignedInt + FiniteRangeNumber + AsBytes> Word for W {}
82
83/// Common methods for [`BitFieldSlice`], [`BitFieldSliceMut`], and [`AtomicBitFieldSlice`].
84///
85/// The dependence on `W` is necessary to implement this trait on vectors and slices, as
86/// we need the bit width of the values stored in the slice.
87pub trait BitFieldSliceCore<W> {
88    /// Returns the width of the slice.
89    ///
90    /// All elements stored in the slice must fit within this bit width.
91    fn bit_width(&self) -> usize;
92    /// Returns the length of the slice.
93    fn len(&self) -> usize;
94    /// Returns true if the slice has length zero.
95    fn is_empty(&self) -> bool {
96        self.len() == 0
97    }
98}
99
100macro_rules! panic_if_out_of_bounds {
101    ($index: expr, $len: expr) => {
102        if $index >= $len {
103            panic!("Index out of bounds: {} >= {}", $index, $len)
104        }
105    };
106}
107pub(crate) use panic_if_out_of_bounds;
108
109macro_rules! panic_if_value {
110    ($value: expr, $mask: expr, $bit_width: expr) => {
111        if $value & $mask != $value {
112            panic!("Value {} does not fit in {} bits", $value, $bit_width);
113        }
114    };
115}
116pub(crate) use panic_if_value;
117
118macro_rules! debug_assert_bounds {
119    ($index: expr, $len: expr) => {
120        debug_assert!(
121            $index < $len || ($index == 0 && $len == 0),
122            "Index out of bounds: {} >= {}",
123            $index,
124            $len
125        );
126    };
127}
128
129/// A slice of bit fields of constant bit width.
130pub trait BitFieldSlice<W: Word>: BitFieldSliceCore<W> {
131    /// Returns the value at the specified index.
132    ///
133    /// # Safety
134    ///
135    /// `index` must be in [0..[len](`BitFieldSliceCore::len`)). No bounds checking is performed.
136    unsafe fn get_unchecked(&self, index: usize) -> W;
137
138    /// Returns the value at the specified index.
139    ///
140    /// # Panics
141    /// May panic if the index is not in in [0..[len](`BitFieldSliceCore::len`))
142    fn get(&self, index: usize) -> W {
143        panic_if_out_of_bounds!(index, self.len());
144        unsafe { self.get_unchecked(index) }
145    }
146}
147
148/// A mutable slice of bit fields of constant bit width.
149pub trait BitFieldSliceMut<W: Word>: BitFieldSlice<W> {
150    /// Returns the mask to apply to values to ensure they fit in
151    /// [`bit_width`](BitFieldSliceCore::bit_width) bits.
152    #[inline(always)]
153    fn mask(&self) -> W {
154        // TODO: Maybe testless?
155        if self.bit_width() == 0 {
156            W::ZERO
157        } else {
158            W::MAX >> (W::BITS as u32 - self.bit_width() as u32)
159        }
160    }
161
162    /// Sets the element of the slice at the specified index.
163    /// No bounds checking is performed.
164    ///
165    /// # Safety
166    /// - `index` must be in [0..[len](`BitFieldSliceCore::len`));
167    /// - `value` must fit withing [`BitFieldSliceCore::bit_width`] bits.
168    ///
169    /// No bound or bit-width check is performed.
170    unsafe fn set_unchecked(&mut self, index: usize, value: W);
171
172    /// Sets the element of the slice at the specified index.
173    ///
174    /// May panic if the index is not in in [0..[len](`BitFieldSliceCore::len`))
175    /// or the value does not fit in [`BitFieldSliceCore::bit_width`] bits.
176    fn set(&mut self, index: usize, value: W) {
177        panic_if_out_of_bounds!(index, self.len());
178        let bit_width = self.bit_width();
179        // TODO: Maybe testless?
180        let mask = if bit_width == 0 {
181            W::ZERO
182        } else {
183            W::MAX >> (W::BITS as u32 - bit_width as u32)
184        };
185
186        panic_if_value!(value, mask, bit_width);
187        unsafe {
188            self.set_unchecked(index, value);
189        }
190    }
191
192    /// Sets all values to zero.
193    fn reset(&mut self);
194
195    /// Sets all values to zero using a parallel implementation.
196    #[cfg(feature = "rayon")]
197    fn par_reset(&mut self);
198
199    /// Copy part of the content of the vector to another vector.
200    ///
201    /// At most `len` elements are copied, compatibly with the elements
202    /// available in both vectors.
203    ///
204    /// # Arguments
205    ///
206    /// * `from`: the index of the first element to copy.
207    ///
208    /// * `dst`: the destination vector.
209    ///
210    /// * `to`: the index of the first element in the destination vector.
211    ///
212    /// * `len`: the maximum number of elements to copy.
213    ///
214    /// # Implementation Notes
215    ///
216    /// The default implementation is a simple loop that copies the elements one
217    /// by one. It is expected to be implemented in a more efficient way.
218    fn copy(&self, from: usize, dst: &mut Self, to: usize, len: usize) {
219        // Reduce len to the elements available in both vectors
220        let len = Ord::min(Ord::min(len, dst.len() - to), self.len() - from);
221        for i in 0..len {
222            dst.set(to + i, self.get(from + i));
223        }
224    }
225
226    /// Applies a function to all elements of the slice in place without
227    /// checking [bit widths](BitFieldSliceCore::bit_width).
228    ///
229    /// This method is semantically equivalent to:
230    /// ```ignore
231    /// for i in 0..self.len() {
232    ///     self.set_unchecked(i, f(self.get_unchecked(i)));
233    /// }
234    /// ```
235    /// and this is indeed the default implementation.
236    ///
237    /// See [`apply_in_place`](BitFieldSliceMut::apply_in_place) for examples.
238    ///
239    /// # Safety
240    /// The function must return a value that fits the the [bit
241    ///  width](BitFieldSliceCore::bit_width) of the slice.
242    unsafe fn apply_in_place_unchecked<F>(&mut self, mut f: F)
243    where
244        F: FnMut(W) -> W,
245        Self: BitFieldSlice<W>,
246    {
247        for idx in 0..self.len() {
248            let value = unsafe { self.get_unchecked(idx) };
249            let new_value = f(value);
250            unsafe { self.set_unchecked(idx, new_value) };
251        }
252    }
253
254    /// Applies a function to all elements of the slice in place.
255    ///
256    /// This method is semantically equivalent to:
257    /// ```ignore
258    /// for i in 0..self.len() {
259    ///     self.set(i, f(self.get(i)));
260    /// }
261    /// ```
262    /// and this is indeed the default implementation.
263    ///
264    /// The function is applied from the first element to the last: thus,
265    /// it possible to compute cumulative sums as follows:
266    ///
267    /// ```rust
268    /// use sux::bits::BitFieldVec;
269    /// use sux::traits::BitFieldSliceMut;
270    ///
271    /// let mut vec = BitFieldVec::<u16>::new(9, 10);
272    ///
273    /// for i in 0..10 {
274    ///     vec.set(i, i as u16);
275    /// }
276    ///
277    /// let mut total = 0;
278    /// vec.apply_in_place(|x| {
279    ///     total += x;
280    ///     total
281    /// });
282    /// ```
283    fn apply_in_place<F>(&mut self, mut f: F)
284    where
285        F: FnMut(W) -> W,
286        Self: BitFieldSlice<W>,
287    {
288        let bit_width = self.bit_width();
289        let mask = self.mask();
290        unsafe {
291            self.apply_in_place_unchecked(|x| {
292                let new_value = f(x);
293                panic_if_value!(new_value, mask, bit_width);
294                new_value
295            });
296        }
297    }
298
299    type ChunksMut<'a>: Iterator<Item: BitFieldSliceMut<W>>
300    where
301        Self: 'a;
302
303    /// Tries and returns an iterator over non-overlapping mutable chunks of a
304    /// bit-field slice, starting at the beginning of the slice.
305    ///
306    /// This might not always be possible; implementations must document when
307    /// the method will success (see, for example, [the implementation for
308    /// `BitFieldVec`](#impl-BitFieldSliceMut-for-BitFieldVec)).
309    ///
310    /// When the slice len is not evenly divided by the chunk size, the last
311    /// chunk of the iteration will be the remainder.
312    ///
313    /// # Examples
314    ///
315    /// ```
316    /// # fn main() -> Result<(), ()> {
317    /// use sux::prelude::*;
318    ///
319    /// let mut b = bit_field_vec![32; 4, 500, 2, 3, 1];
320    /// for mut c in b.try_chunks_mut(2)? {
321    ///     c.set(0, 5);
322    /// }
323    /// assert_eq!(b, bit_field_vec![32; 5, 500, 5, 3, 5]);
324    /// # Ok(())
325    /// # }
326    /// ```
327    fn try_chunks_mut(&mut self, chunk_size: usize) -> Result<Self::ChunksMut<'_>, ()>;
328
329    /// Returns the backend of the slice as a mutable slice of `W`.
330    fn as_mut_slice(&mut self) -> &mut [W];
331}
332
333/// A (tentatively) thread-safe slice of bit fields of constant bit width supporting atomic operations.
334///
335/// Different implementations might provide different atomicity guarantees. See
336/// [`BitFieldVec`](crate::bits::bit_field_vec::BitFieldVec) for an example.
337pub trait AtomicBitFieldSlice<W: Word + IntoAtomic>: BitFieldSliceCore<W::AtomicType>
338where
339    W::AtomicType: AtomicUnsignedInt + AsBytes,
340{
341    /// Returns the value at the specified index.
342    ///
343    /// # Safety
344    /// `index` must be in [0..[len](`BitFieldSliceCore::len`)).
345    /// No bound or bit-width check is performed.
346    unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> W;
347
348    /// Returns the value at the specified index.
349    ///
350    /// # Panics
351    /// May panic if the index is not in in [0..[len](`BitFieldSliceCore::len`))
352    fn get_atomic(&self, index: usize, order: Ordering) -> W {
353        panic_if_out_of_bounds!(index, self.len());
354        unsafe { self.get_atomic_unchecked(index, order) }
355    }
356
357    /// Sets the element of the slice at the specified index.
358    ///
359    /// # Safety
360    /// - `index` must be in [0..[len](`BitFieldSliceCore::len`));
361    /// - `value` must fit withing [`BitFieldSliceCore::bit_width`] bits.
362    ///
363    /// No bound or bit-width check is performed.
364    unsafe fn set_atomic_unchecked(&self, index: usize, value: W, order: Ordering);
365
366    /// Sets the element of the slice at the specified index.
367    ///
368    /// May panic if the index is not in in [0..[len](`BitFieldSliceCore::len`))
369    /// or the value does not fit in [`BitFieldSliceCore::bit_width`] bits.
370    fn set_atomic(&self, index: usize, value: W, order: Ordering) {
371        if index >= self.len() {
372            panic_if_out_of_bounds!(index, self.len());
373        }
374        let bw = self.bit_width();
375
376        let mask = if bw == 0 {
377            W::ZERO
378        } else {
379            W::MAX >> (W::BITS as u32 - bw as u32)
380        };
381        panic_if_value!(value, mask, bw);
382        unsafe {
383            self.set_atomic_unchecked(index, value, order);
384        }
385    }
386
387    /// Sets all values to zero.
388    ///
389    /// This method takes an exclusive reference because usually one needs to
390    /// reset a vector to reuse it, and the mutable reference makes it
391    /// impossible to have any other reference hanging around.
392    fn reset_atomic(&mut self, order: Ordering);
393
394    /// Sets all values to zero using a parallel implementation.
395    ///
396    /// See [`reset_atomic`](AtomicBitFieldSlice::reset_atomic) for more
397    /// details.
398    #[cfg(feature = "rayon")]
399    fn par_reset_atomic(&mut self, order: Ordering);
400}
401
402/// An [`Iterator`] implementation returning the elements of a [`BitFieldSlice`].
403///
404/// You can easily implement [`IntoIterator`] on a reference to your type using this structure.
405#[derive(Debug, Clone, MemDbg, MemSize)]
406pub struct BitFieldSliceIterator<'a, W: Word, B: BitFieldSlice<W>> {
407    slice: &'a B,
408    index: usize,
409    _marker: PhantomData<W>,
410}
411
412impl<'a, V: Word, B: BitFieldSlice<V>> BitFieldSliceIterator<'a, V, B> {
413    pub fn new(slice: &'a B, from: usize) -> Self {
414        if from > slice.len() {
415            panic!("Start index out of bounds: {} > {}", from, slice.len());
416        }
417        Self {
418            slice,
419            index: from,
420            _marker: PhantomData,
421        }
422    }
423}
424
425impl<W: Word, B: BitFieldSlice<W>> Iterator for BitFieldSliceIterator<'_, W, B> {
426    type Item = W;
427    fn next(&mut self) -> Option<Self::Item> {
428        if self.index < self.slice.len() {
429            // SAFETY: self.index is always within bounds
430            let res = unsafe { self.slice.get_unchecked(self.index) };
431            self.index += 1;
432            Some(res)
433        } else {
434            None
435        }
436    }
437}
438
439// Implementations for slices of non-atomic types
440
441macro_rules! impl_core {
442    ($($ty:ty),*) => {$(
443        impl<T: AsRef<[$ty]>> BitFieldSliceCore<$ty> for T {
444            #[inline(always)]
445            fn bit_width(&self) -> usize {
446                <$ty>::BITS as usize
447            }
448            #[inline(always)]
449            fn len(&self) -> usize {
450                self.as_ref().len()
451            }
452        }
453    )*};
454}
455
456impl_core!(u8, u16, u32, u64, u128, usize);
457// This implementation is not necessary, but it avoids ambiguity
458// with expressions like [1, 2, 3].len() when using the prelude.
459// Without this implementation, the compiler complains that
460// BitFieldSliceCore is not implemented for [i32; 3].
461impl_core!(i8, i16, i32, i64, i128, isize);
462
463macro_rules! impl_ref {
464    ($($ty:ty),*) => {$(
465        impl<T: AsRef<[$ty]>> BitFieldSlice<$ty> for T {
466            #[inline(always)]
467            unsafe fn get_unchecked(&self, index: usize) -> $ty {
468                debug_assert_bounds!(index, self.len());
469                *self.as_ref().get_unchecked(index)
470            }
471        }
472    )*};
473}
474
475impl_ref!(u8, u16, u32, u64, u128, usize);
476
477macro_rules! impl_mut {
478    ($($ty:ty),*) => {$(
479        impl<T: AsMut<[$ty]> + AsRef<[$ty]>> BitFieldSliceMut<$ty> for T {
480            #[inline(always)]
481            unsafe fn set_unchecked(&mut self, index: usize, value: $ty) {
482                debug_assert_bounds!(index, self.len());
483                *self.as_mut().get_unchecked_mut(index) = value;
484            }
485
486            fn reset(&mut self) {
487                for idx in 0..self.len() {
488                    unsafe{self.set_unchecked(idx, 0)};
489                }
490            }
491
492            #[cfg(feature = "rayon")]
493            fn par_reset(&mut self) {
494                self.as_mut()
495                    .par_iter_mut()
496                    .with_min_len(crate::RAYON_MIN_LEN)
497                    .for_each(|w| { *w = 0 });
498            }
499
500            fn copy(&self, from: usize, dst: &mut Self, to: usize, len: usize) {
501                let len = Ord::min(Ord::min(len, dst.len() - to), self.len() - from);
502                dst.as_mut()[to..][..len].copy_from_slice(&self.as_ref()[from..][..len]);
503            }
504
505            type ChunksMut<'a> = std::slice::ChunksMut<'a, $ty> where Self: 'a;
506
507            fn try_chunks_mut(&mut self, chunk_size: usize) -> Result<Self::ChunksMut<'_>, ()> {
508                Ok(self.as_mut().chunks_mut(chunk_size))
509            }
510
511            fn as_mut_slice(&mut self) -> &mut [$ty] {
512                self.as_mut()
513            }
514        }
515    )*};
516}
517
518impl_mut!(u8, u16, u32, u64, u128, usize);
519
520// Implementations for slices of atomic types
521
522macro_rules! impl_core_atomic {
523    ($($aty:ty),*) => {$(
524        impl<T: AsRef<[$aty]>> BitFieldSliceCore<$aty> for T {
525            #[inline(always)]
526            fn bit_width(&self) -> usize {
527                <$aty>::BITS as usize
528            }
529            #[inline(always)]
530            fn len(&self) -> usize {
531                self.as_ref().len()
532            }
533        }
534    )*};
535}
536
537impl_core_atomic!(AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize);
538
539macro_rules! impl_atomic {
540    ($std:ty, $atomic:ty) => {
541        impl<T: AsRef<[$atomic]>> AtomicBitFieldSlice<$std> for T {
542            #[inline(always)]
543            unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> $std {
544                debug_assert_bounds!(index, self.len());
545                self.as_ref().get_unchecked(index).load(order)
546            }
547            #[inline(always)]
548            unsafe fn set_atomic_unchecked(&self, index: usize, value: $std, order: Ordering) {
549                debug_assert_bounds!(index, self.len());
550                self.as_ref().get_unchecked(index).store(value, order);
551            }
552
553            fn reset_atomic(&mut self, order: Ordering) {
554                for idx in 0..self.len() {
555                    unsafe { self.set_atomic_unchecked(idx, 0, order) };
556                }
557            }
558
559            #[cfg(feature = "rayon")]
560            fn par_reset_atomic(&mut self, order: Ordering) {
561                self.as_ref()
562                    .par_iter()
563                    .with_min_len(crate::RAYON_MIN_LEN)
564                    .for_each(|w| w.store(0, order));
565            }
566        }
567    };
568}
569
570impl_atomic!(u8, AtomicU8);
571impl_atomic!(u16, AtomicU16);
572impl_atomic!(u32, AtomicU32);
573impl_atomic!(u64, AtomicU64);
574impl_atomic!(usize, AtomicUsize);
575
576/// Helper trait eliminating `_atomic` from all methods of [`AtomicBitFieldSlice`]
577/// using a blanked implementation.
578///
579/// Note that using this trait and [`BitFieldSlice`] in the same module might cause
580/// ambiguity problems.
581pub trait AtomicHelper<W: Word + IntoAtomic>: AtomicBitFieldSlice<W>
582where
583    W::AtomicType: AtomicUnsignedInt + AsBytes,
584{
585    /// Delegates to [`AtomicBitFieldSlice::get_atomic_unchecked`]
586    /// # Safety
587    /// See [`AtomicBitFieldSlice::get_atomic_unchecked`]
588    #[inline(always)]
589    unsafe fn get_unchecked(&self, index: usize, order: Ordering) -> W {
590        self.get_atomic_unchecked(index, order)
591    }
592
593    /// Delegates to [`AtomicBitFieldSlice::set_atomic`]
594    #[inline(always)]
595    fn get(&self, index: usize, order: Ordering) -> W {
596        self.get_atomic(index, order)
597    }
598
599    /// Delegates to [`AtomicBitFieldSlice::set_atomic_unchecked`]
600    /// # Safety
601    /// See [`AtomicBitFieldSlice::get_atomic_unchecked`]
602    #[inline(always)]
603    unsafe fn set_unchecked(&self, index: usize, value: W, order: Ordering) {
604        self.set_atomic_unchecked(index, value, order)
605    }
606
607    /// Delegates to [`AtomicBitFieldSlice::set_atomic`]
608    #[inline(always)]
609    fn set(&self, index: usize, value: W, order: Ordering) {
610        self.set_atomic(index, value, order)
611    }
612
613    /// Delegates to [`AtomicBitFieldSlice::reset_atomic`]
614    #[inline(always)]
615    fn reset(&mut self, order: Ordering) {
616        self.reset_atomic(order);
617    }
618}
619
620impl<T, W: Word + IntoAtomic> AtomicHelper<W> for T
621where
622    T: AtomicBitFieldSlice<W>,
623    W::AtomicType: AtomicUnsignedInt + AsBytes,
624{
625}