#![allow(clippy::result_unit_err)]
use common_traits::*;
use core::sync::atomic::*;
#[cfg(feature = "rayon")]
use rayon::iter::{
IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator,
};
use value_traits::slices::{SliceByValue, SliceByValueMut};
use crate::{debug_assert_bounds, panic_if_out_of_bounds, panic_if_value};
pub trait Word: UnsignedInt + FiniteRangeNumber + AsBytes {}
impl<W: UnsignedInt + FiniteRangeNumber + AsBytes> Word for W {}
pub trait BitWidth<W> {
fn bit_width(&self) -> usize;
}
pub trait BitFieldSlice<W: Word>: SliceByValue<Value = W> + BitWidth<W> {
fn as_slice(&self) -> &[W];
}
pub trait BitFieldSliceMut<W: Word>: BitFieldSlice<W> + SliceByValueMut<Value = W> {
#[inline(always)]
fn mask(&self) -> W {
if self.bit_width() == 0 {
W::ZERO
} else {
W::MAX >> (W::BITS as u32 - self.bit_width() as u32)
}
}
fn reset(&mut self);
#[cfg(feature = "rayon")]
fn par_reset(&mut self);
fn as_mut_slice(&mut self) -> &mut [W];
}
pub trait AtomicBitFieldSlice<W: Word + IntoAtomic>: BitWidth<W::AtomicType>
where
W::AtomicType: AtomicUnsignedInt + AsBytes,
{
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> W;
fn get_atomic(&self, index: usize, order: Ordering) -> W {
panic_if_out_of_bounds!(index, self.len());
unsafe { self.get_atomic_unchecked(index, order) }
}
unsafe fn set_atomic_unchecked(&self, index: usize, value: W, order: Ordering);
fn set_atomic(&self, index: usize, value: W, order: Ordering) {
panic_if_out_of_bounds!(index, self.len());
let bw = self.bit_width();
let mask = if bw == 0 {
W::ZERO
} else {
W::MAX >> (W::BITS as u32 - 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);
}
macro_rules! impl_bit_width {
($($ty:ty),*) => {$(
impl BitWidth<$ty> for [$ty] {
#[inline(always)]
fn bit_width(&self) -> usize {
<$ty>::BITS as usize
}
}
impl BitWidth<$ty> for Vec<$ty> {
#[inline(always)]
fn bit_width(&self) -> usize {
<$ty>::BITS as usize
}
}
impl<const N: usize> BitWidth<$ty> for [$ty; N] {
#[inline(always)]
fn bit_width(&self) -> usize {
<$ty>::BITS as usize
}
}
)*};
}
impl_bit_width!(u8, u16, u32, u64, u128, usize);
macro_rules! impl_bit_width_delegation {
($($ty:ty),*) => {$(
impl<W, T: BitWidth<W> + ?Sized> BitWidth<W> for $ty {
#[inline(always)]
fn bit_width(&self) -> usize {
T::bit_width(self)
}
}
)*}}
impl_bit_width_delegation!(&T, &mut T, Box<T>);
macro_rules! impl_slice {
($($ty:ty),*) => {$(
impl BitFieldSlice<$ty> for [$ty] {
fn as_slice(&self) -> &[$ty] {
self
}
}
impl BitFieldSlice<$ty> for Vec<$ty> {
fn as_slice(&self) -> &[$ty] {
self
}
}
impl<const N: usize> BitFieldSlice<$ty> for [$ty; N] {
fn as_slice(&self) -> &[$ty] {
self
}
}
)*};
}
impl_slice!(u8, u16, u32, u64, u128, usize);
macro_rules! impl_slice_delegation {
($($ty:ty),*) => {$(
impl<W: Word, T: BitFieldSlice<W> + ?Sized> BitFieldSlice<W> for $ty {
#[inline(always)]
fn as_slice(&self) -> &[W] {
T::as_slice(self)
}
}
)*}}
impl_slice_delegation!(&T, &mut T, Box<T>);
macro_rules! impl_slice_mut {
($($ty:ty),*) => {$(
impl BitFieldSliceMut<$ty> for [$ty] {
fn reset(&mut self) {
for idx in 0..<[$ty]>::len(self) {
unsafe{ self.set_unchecked(idx, 0) };
}
}
#[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 = 0 });
}
fn as_mut_slice(&mut self) -> &mut [$ty] {
self
}
}
impl BitFieldSliceMut<$ty> for Vec<$ty> {
#[inline(always)]
fn reset(&mut self) {
for idx in 0..<[$ty]>::len(self) {
unsafe{ self.set_unchecked(idx, 0) };
}
}
#[cfg(feature = "rayon")]
fn par_reset(&mut self) {
self
.par_iter_mut()
.with_min_len(crate::RAYON_MIN_LEN)
.for_each(|w| { *w = 0 });
}
fn as_mut_slice(&mut self) -> &mut [$ty] {
self
}
}
impl<const N: usize> BitFieldSliceMut<$ty> for [$ty; N] {
#[inline(always)]
fn reset(&mut self) {
for idx in 0..<[$ty]>::len(self) {
unsafe{ self.set_unchecked(idx, 0) };
}
}
#[cfg(feature = "rayon")]
fn par_reset(&mut self) {
self
.par_iter_mut()
.with_min_len(crate::RAYON_MIN_LEN)
.for_each(|w| { *w = 0 });
}
fn as_mut_slice(&mut self) -> &mut [$ty] {
self
}
}
)*};
}
impl_slice_mut!(u8, u16, u32, u64, u128, usize);
macro_rules! impl_slice_mut_delegation {
($($ty:ty),*) => {$(
impl<W: Word, T: BitFieldSliceMut<W> + ?Sized> BitFieldSliceMut<W> for $ty {
#[inline(always)]
fn reset(&mut self) {
T::reset(self)
}
#[cfg(feature = "rayon")]
#[inline(always)]
fn par_reset(&mut self) {
T::par_reset(self)
}
#[inline(always)]
fn as_mut_slice(&mut self) -> &mut [W] {
T::as_mut_slice(self)
}
}
)*}}
impl_slice_mut_delegation!(&mut T, Box<T>);
macro_rules! impl_bit_width_atomic {
($($aty:ty),*) => {$(
impl BitWidth<$aty> for [$aty] {
#[inline(always)]
fn bit_width(&self) -> usize {
<$aty>::BITS as usize
}
}
impl BitWidth<$aty> for Vec<$aty> {
#[inline(always)]
fn bit_width(&self) -> usize {
<$aty>::BITS as usize
}
}
impl<const N: usize> BitWidth<$aty> for [$aty; N] {
#[inline(always)]
fn bit_width(&self) -> usize {
<$aty>::BITS as usize
}
}
)*};
}
impl_bit_width_atomic!(AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize);
macro_rules! impl_atomic {
($std:ty, $atomic:ty) => {
impl AtomicBitFieldSlice<$std> for [$atomic] {
#[inline(always)]
fn len(&self) -> usize {
self.as_ref().len()
}
#[inline(always)]
unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> $std {
debug_assert_bounds!(index, self.len());
unsafe { self.as_ref().get_unchecked(index).load(order) }
}
#[inline(always)]
unsafe fn set_atomic_unchecked(&self, index: usize, value: $std, order: Ordering) {
debug_assert_bounds!(index, self.len());
unsafe {
self.as_ref().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, 0, order) };
}
}
#[cfg(feature = "rayon")]
fn par_reset_atomic(&mut self, order: Ordering) {
self.as_ref()
.par_iter()
.with_min_len(crate::RAYON_MIN_LEN)
.for_each(|w| w.store(0, order));
}
}
impl AtomicBitFieldSlice<$std> for Vec<$atomic> {
#[inline(always)]
fn len(&self) -> usize {
self.len()
}
#[inline(always)]
unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> $std {
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: $std, 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, 0, 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(0, order));
}
}
impl<const N: usize> AtomicBitFieldSlice<$std> for [$atomic; N] {
#[inline(always)]
fn len(&self) -> usize {
N
}
#[inline(always)]
unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> $std {
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: $std, 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, 0, 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(0, order));
}
}
};
}
impl_atomic!(u8, AtomicU8);
impl_atomic!(u16, AtomicU16);
impl_atomic!(u32, AtomicU32);
impl_atomic!(u64, AtomicU64);
impl_atomic!(usize, AtomicUsize);
macro_rules! impl_atomic_delegation {
($($ty:ty),*) => {$(
impl<W: Word + IntoAtomic, T: AtomicBitFieldSlice<W>> AtomicBitFieldSlice<W> for $ty
where
W::AtomicType: AtomicUnsignedInt + AsBytes
{
#[inline(always)]
fn len(&self) -> usize {
T::len(self)
}
#[inline(always)]
unsafe fn get_atomic_unchecked(&self, index: usize, order: Ordering) -> W {
unsafe { T::get_atomic_unchecked(self, index, order) }
}
#[inline(always)]
fn get_atomic(&self, index: usize, order: Ordering) -> W {
T::get_atomic(self, index, order)
}
#[inline(always)]
unsafe fn set_atomic_unchecked(&self, index: usize, value: W, order: Ordering) {
unsafe { T::set_atomic_unchecked(self, index, value, order) }
}
#[inline(always)]
fn set_atomic(&self, index: usize, value: W, order: Ordering) {
T::set_atomic(self, index, value, order)
}
#[inline(always)]
fn reset_atomic(&mut self, order: Ordering) {
T::reset_atomic(self, order)
}
#[inline(always)]
#[cfg(feature = "rayon")]
fn par_reset_atomic(&mut self, order: Ordering) {
T::par_reset_atomic(self, order)
}
}
)*}}
impl_atomic_delegation!(&mut T, Box<T>);