#![allow(clippy::cast_sign_loss)]
#![allow(clippy::cast_possible_wrap)]
mod arch {
#[cfg(all(target_arch = "x86", target_feature = "bmi2"))]
pub use core::arch::x86::*;
#[cfg(all(target_arch = "x86_64", target_feature = "bmi2"))]
pub use core::arch::x86_64::*;
}
pub trait Pdep {
fn pdep(self, mask: Self) -> Self;
}
macro_rules! impl_all {
($impl_macro:ident: $($id:ident),*) => {
$(
$impl_macro!($id);
)*
}
}
macro_rules! cfg_if {
($(
if #[cfg($($meta:meta),*)] { $($it:item)* }
) else * else {
$($it2:item)*
}) => {
cfg_if! {
@__items
() ;
$( ( ($($meta),*) ($($it)*) ), )*
( () ($($it2)*) ),
}
};
(
if #[cfg($($i_met:meta),*)] { $($i_it:item)* }
$(
else if #[cfg($($e_met:meta),*)] { $($e_it:item)* }
)*
) => {
cfg_if! {
@__items
() ;
( ($($i_met),*) ($($i_it)*) ),
$( ( ($($e_met),*) ($($e_it)*) ), )*
( () () ),
}
};
(@__items ($($not:meta,)*) ; ) => {};
(@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* }
cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* }
};
(@__apply $m:meta, $($it:item)*) => {
$(#[$m] $it)*
};
}
macro_rules! pdep_impl {
($ty:ty) => {
#[inline]
fn pdep_(value: $ty, mut mask: $ty) -> $ty {
let mut res = 0;
let mut bb: $ty = 1;
loop {
if mask == 0 {
break;
}
if (value & bb) != 0 {
res |= mask & mask.wrapping_neg();
}
mask &= mask - 1;
bb = bb.wrapping_add(bb);
}
res
}
};
($ty:ty, $intr:ident) => {
cfg_if! {
if #[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "bmi2"
))] {
#[inline]
#[target_feature(enable = "bmi2")]
unsafe fn pdep_(value: $ty, mask: $ty) -> $ty {
crate::util::pdep::arch::$intr(
value as _,
mask as _,
) as _
}
} else {
pdep_impl!($ty);
}
}
};
}
macro_rules! impl_pdep {
($id:ident $(,$args:ident)*) => {
impl Pdep for $id {
#[inline]
#[allow(unused_unsafe)]
fn pdep(self, mask: Self) -> Self {
pdep_impl!($id $(,$args)*);
unsafe { pdep_(self, mask) }
}
}
}
}
impl_all!(impl_pdep: u8, u16, i8, i16);
cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
impl_pdep!(u32, _pdep_u32);
impl_pdep!(i32, _pdep_u32);
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
impl_pdep!(u64, _pdep_u64);
impl_pdep!(i64, _pdep_u64);
} else {
impl_all!(impl_pdep: i64, u64);
}
}
} else {
impl_all!(impl_pdep: u32, i32, i64, u64);
}
}