#![allow(clippy::result_unit_err)]
use crate::{debug_assert_bounds, panic_if_out_of_bounds, panic_if_value, traits::Word};
use ambassador::delegatable_trait;
use atomic_primitive::PrimitiveAtomicUnsigned;
use core::sync::atomic::Ordering;
use impl_tools::autoimpl;
use num_primitive::PrimitiveInteger;
#[cfg(feature = "rayon")]
use rayon::iter::{
IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator,
};
use value_traits::slices::{SliceByValue, SliceByValueMut};
#[delegatable_trait]
#[autoimpl(for<T: trait + ?Sized> &T, &mut T, Box<T>)]
pub trait BitWidth {
fn bit_width(&self) -> usize;
}
#[delegatable_trait]
#[autoimpl(for<T: trait + ?Sized> &T, &mut T, Box<T>)]
pub trait BitFieldSlice: SliceByValue + BitWidth {
fn as_slice(&self) -> &[Self::Value];
}
#[autoimpl(for<T: trait + ?Sized> &mut T, Box<T>)]
pub trait BitFieldSliceMut: BitFieldSlice + SliceByValueMut {
fn reset(&mut self);
#[cfg(feature = "rayon")]
fn par_reset(&mut self);
fn as_mut_slice(&mut self) -> &mut [Self::Value];
}
#[inline(always)]
pub fn mask<W: Word>(bit_width: usize) -> W {
if bit_width == 0 {
W::ZERO
} else {
W::MAX >> (W::BITS - bit_width as u32)
}
}
#[autoimpl(for<T: trait + ?Sized> &T, &mut T, Box<T>)]
pub trait AtomicBitWidth {
fn atomic_bit_width(&self) -> usize;
}
impl<A: PrimitiveAtomicUnsigned> AtomicBitWidth for [A] {
#[inline(always)]
fn atomic_bit_width(&self) -> usize {
A::BITS as usize
}
}
impl<A: PrimitiveAtomicUnsigned> AtomicBitWidth for Vec<A> {
#[inline(always)]
fn atomic_bit_width(&self) -> usize {
A::BITS as usize
}
}
impl<A: PrimitiveAtomicUnsigned, const N: usize> AtomicBitWidth for [A; N] {
#[inline(always)]
fn atomic_bit_width(&self) -> usize {
A::BITS as usize
}
}
#[autoimpl(for<T: trait + ?Sized> &mut T, Box<T>)]
pub trait AtomicBitFieldSlice<A: PrimitiveAtomicUnsigned<Value: Word>>: AtomicBitWidth {
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> A::Value;
fn get_atomic(&self, index: usize, order: Ordering) -> A::Value {
panic_if_out_of_bounds!(index, self.len());
unsafe { self.get_atomic_unchecked(index, order) }
}
unsafe fn set_atomic_unchecked(&self, index: usize, value: A::Value, order: Ordering);
fn set_atomic(&self, index: usize, value: A::Value, order: Ordering) {
panic_if_out_of_bounds!(index, self.len());
let bw = self.atomic_bit_width();
let mask = if bw == 0 {
A::Value::ZERO
} else {
A::Value::MAX >> (A::Value::BITS - bw as u32)
};
panic_if_value!(value, mask, bw);
unsafe {
self.set_atomic_unchecked(index, value, order);
}
}
fn reset_atomic(&mut self, order: Ordering);
#[cfg(feature = "rayon")]
fn par_reset_atomic(&mut self, order: Ordering);
}
impl<W: Word> BitWidth for [W] {
#[inline(always)]
fn bit_width(&self) -> usize {
W::BITS as usize
}
}
impl<W: Word> BitWidth for Vec<W> {
#[inline(always)]
fn bit_width(&self) -> usize {
W::BITS as usize
}
}
impl<W: Word, const N: usize> BitWidth for [W; N] {
#[inline(always)]
fn bit_width(&self) -> usize {
W::BITS as usize
}
}
impl<W: Word> BitFieldSlice for [W] {
fn as_slice(&self) -> &[W] {
self
}
}
impl<W: Word> BitFieldSlice for Vec<W> {
fn as_slice(&self) -> &[W] {
self
}
}
impl<W: Word, const N: usize> BitFieldSlice for [W; N] {
fn as_slice(&self) -> &[W] {
self
}
}
impl<W: Word> BitFieldSliceMut for [W] {
fn reset(&mut self) {
self.fill(W::ZERO);
}
#[cfg(feature = "rayon")]
fn par_reset(&mut self) {
self.as_mut()
.par_iter_mut()
.with_min_len(crate::RAYON_MIN_LEN)
.for_each(|w| *w = W::ZERO);
}
fn as_mut_slice(&mut self) -> &mut [W] {
self
}
}
impl<W: Word> BitFieldSliceMut for Vec<W> {
#[inline(always)]
fn reset(&mut self) {
self.fill(W::ZERO);
}
#[cfg(feature = "rayon")]
fn par_reset(&mut self) {
self.par_iter_mut()
.with_min_len(crate::RAYON_MIN_LEN)
.for_each(|w| *w = W::ZERO);
}
fn as_mut_slice(&mut self) -> &mut [W] {
self
}
}
impl<W: Word, const N: usize> BitFieldSliceMut for [W; N] {
#[inline(always)]
fn reset(&mut self) {
self.fill(W::ZERO);
}
#[cfg(feature = "rayon")]
fn par_reset(&mut self) {
self.par_iter_mut()
.with_min_len(crate::RAYON_MIN_LEN)
.for_each(|w| *w = W::ZERO);
}
fn as_mut_slice(&mut self) -> &mut [W] {
self
}
}
impl<A: PrimitiveAtomicUnsigned<Value: Word>> AtomicBitFieldSlice<A> for [A] {
#[inline(always)]
fn len(&self) -> usize {
<[A]>::len(self)
}
#[inline(always)]
unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> A::Value {
debug_assert_bounds!(index, self.len());
unsafe { self.get_unchecked(index).load(order) }
}
#[inline(always)]
unsafe fn set_atomic_unchecked(&self, index: usize, value: A::Value, order: Ordering) {
debug_assert_bounds!(index, self.len());
unsafe {
self.get_unchecked(index).store(value, order);
}
}
fn reset_atomic(&mut self, order: Ordering) {
for idx in 0..self.len() {
unsafe { self.set_atomic_unchecked(idx, A::Value::ZERO, order) };
}
}
#[cfg(feature = "rayon")]
fn par_reset_atomic(&mut self, order: Ordering) {
self.par_iter()
.with_min_len(crate::RAYON_MIN_LEN)
.for_each(|w| w.store(A::Value::ZERO, order));
}
}
impl<A: PrimitiveAtomicUnsigned<Value: Word>> AtomicBitFieldSlice<A> for Vec<A> {
#[inline(always)]
fn len(&self) -> usize {
Vec::len(self)
}
#[inline(always)]
unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> A::Value {
debug_assert_bounds!(index, self.len());
unsafe { self.as_slice().get_unchecked(index).load(order) }
}
#[inline(always)]
unsafe fn set_atomic_unchecked(&self, index: usize, value: A::Value, order: Ordering) {
debug_assert_bounds!(index, self.len());
unsafe {
self.as_slice().get_unchecked(index).store(value, order);
}
}
fn reset_atomic(&mut self, order: Ordering) {
for idx in 0..self.len() {
unsafe { self.set_atomic_unchecked(idx, A::Value::ZERO, order) };
}
}
#[cfg(feature = "rayon")]
fn par_reset_atomic(&mut self, order: Ordering) {
self.par_iter()
.with_min_len(crate::RAYON_MIN_LEN)
.for_each(|w| w.store(A::Value::ZERO, order));
}
}
impl<A: PrimitiveAtomicUnsigned<Value: Word>, const N: usize> AtomicBitFieldSlice<A> for [A; N] {
#[inline(always)]
fn len(&self) -> usize {
N
}
#[inline(always)]
unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> A::Value {
debug_assert_bounds!(index, self.len());
unsafe { self.as_slice().get_unchecked(index).load(order) }
}
#[inline(always)]
unsafe fn set_atomic_unchecked(&self, index: usize, value: A::Value, order: Ordering) {
debug_assert_bounds!(index, self.len());
unsafe {
self.as_slice().get_unchecked(index).store(value, order);
}
}
fn reset_atomic(&mut self, order: Ordering) {
for idx in 0..self.len() {
unsafe { self.set_atomic_unchecked(idx, A::Value::ZERO, order) };
}
}
#[cfg(feature = "rayon")]
fn par_reset_atomic(&mut self, order: Ordering) {
self.par_iter()
.with_min_len(crate::RAYON_MIN_LEN)
.for_each(|w| w.store(A::Value::ZERO, order));
}
}