Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: Apache-2.0 OR MIT
  2
  3use core::num::{Saturating, Wrapping};
  4
  5use crate::boxed::Box;
  6
  7#[rustc_specialization_trait]
  8pub(super) unsafe trait IsZero {
  9    /// Whether this value's representation is all zeros,
 10    /// or can be represented with all zeroes.
 11    fn is_zero(&self) -> bool;
 12}
 13
 14macro_rules! impl_is_zero {
 15    ($t:ty, $is_zero:expr) => {
 16        unsafe impl IsZero for $t {
 17            #[inline]
 18            fn is_zero(&self) -> bool {
 19                $is_zero(*self)
 20            }
 21        }
 22    };
 23}
 24
 25impl_is_zero!(i8, |x| x == 0); // It is needed to impl for arrays and tuples of i8.
 26impl_is_zero!(i16, |x| x == 0);
 27impl_is_zero!(i32, |x| x == 0);
 28impl_is_zero!(i64, |x| x == 0);
 29impl_is_zero!(i128, |x| x == 0);
 30impl_is_zero!(isize, |x| x == 0);
 31
 32impl_is_zero!(u8, |x| x == 0); // It is needed to impl for arrays and tuples of u8.
 33impl_is_zero!(u16, |x| x == 0);
 34impl_is_zero!(u32, |x| x == 0);
 35impl_is_zero!(u64, |x| x == 0);
 36impl_is_zero!(u128, |x| x == 0);
 37impl_is_zero!(usize, |x| x == 0);
 38
 39impl_is_zero!(bool, |x| x == false);
 40impl_is_zero!(char, |x| x == '\0');
 41
 42impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
 43impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
 44
 45unsafe impl<T> IsZero for *const T {
 46    #[inline]
 47    fn is_zero(&self) -> bool {
 48        (*self).is_null()
 49    }
 50}
 51
 52unsafe impl<T> IsZero for *mut T {
 53    #[inline]
 54    fn is_zero(&self) -> bool {
 55        (*self).is_null()
 56    }
 57}
 58
 59unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
 60    #[inline]
 61    fn is_zero(&self) -> bool {
 62        // Because this is generated as a runtime check, it's not obvious that
 63        // it's worth doing if the array is really long. The threshold here
 64        // is largely arbitrary, but was picked because as of 2022-07-01 LLVM
 65        // fails to const-fold the check in `vec![[1; 32]; n]`
 66        // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
 67        // Feel free to tweak if you have better evidence.
 68
 69        N <= 16 && self.iter().all(IsZero::is_zero)
 70    }
 71}
 72
 73// This is recursive macro.
 74macro_rules! impl_for_tuples {
 75    // Stopper
 76    () => {
 77        // No use for implementing for empty tuple because it is ZST.
 78    };
 79    ($first_arg:ident $(,$rest:ident)*) => {
 80        unsafe impl <$first_arg: IsZero, $($rest: IsZero,)*> IsZero for ($first_arg, $($rest,)*){
 81            #[inline]
 82            fn is_zero(&self) -> bool{
 83                // Destructure tuple to N references
 84                // Rust allows to hide generic params by local variable names.
 85                #[allow(non_snake_case)]
 86                let ($first_arg, $($rest,)*) = self;
 87
 88                $first_arg.is_zero()
 89                    $( && $rest.is_zero() )*
 90            }
 91        }
 92
 93        impl_for_tuples!($($rest),*);
 94    }
 95}
 96
 97impl_for_tuples!(A, B, C, D, E, F, G, H);
 98
 99// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
100// For fat pointers, the bytes that would be the pointer metadata in the `Some`
101// variant are padding in the `None` variant, so ignoring them and
102// zero-initializing instead is ok.
103// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
104// `SpecFromElem`.
105
106unsafe impl<T: ?Sized> IsZero for Option<&T> {
107    #[inline]
108    fn is_zero(&self) -> bool {
109        self.is_none()
110    }
111}
112
113unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
114    #[inline]
115    fn is_zero(&self) -> bool {
116        self.is_none()
117    }
118}
119
120// `Option<num::NonZeroU32>` and similar have a representation guarantee that
121// they're the same size as the corresponding `u32` type, as well as a guarantee
122// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
123// While the documentation officially makes it UB to transmute from `None`,
124// we're the standard library so we can make extra inferences, and we know that
125// the only niche available to represent `None` is the one that's all zeros.
126
127macro_rules! impl_is_zero_option_of_nonzero {
128    ($($t:ident,)+) => {$(
129        unsafe impl IsZero for Option<core::num::$t> {
130            #[inline]
131            fn is_zero(&self) -> bool {
132                self.is_none()
133            }
134        }
135    )+};
136}
137
138impl_is_zero_option_of_nonzero!(
139    NonZeroU8,
140    NonZeroU16,
141    NonZeroU32,
142    NonZeroU64,
143    NonZeroU128,
144    NonZeroI8,
145    NonZeroI16,
146    NonZeroI32,
147    NonZeroI64,
148    NonZeroI128,
149    NonZeroUsize,
150    NonZeroIsize,
151);
152
153macro_rules! impl_is_zero_option_of_num {
154    ($($t:ty,)+) => {$(
155        unsafe impl IsZero for Option<$t> {
156            #[inline]
157            fn is_zero(&self) -> bool {
158                const {
159                    let none: Self = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
160                    assert!(none.is_none());
161                }
162                self.is_none()
163            }
164        }
165    )+};
166}
167
168impl_is_zero_option_of_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize,);
169
170unsafe impl<T: IsZero> IsZero for Wrapping<T> {
171    #[inline]
172    fn is_zero(&self) -> bool {
173        self.0.is_zero()
174    }
175}
176
177unsafe impl<T: IsZero> IsZero for Saturating<T> {
178    #[inline]
179    fn is_zero(&self) -> bool {
180        self.0.is_zero()
181    }
182}
183
184macro_rules! impl_for_optional_bool {
185    ($($t:ty,)+) => {$(
186        unsafe impl IsZero for $t {
187            #[inline]
188            fn is_zero(&self) -> bool {
189                // SAFETY: This is *not* a stable layout guarantee, but
190                // inside `core` we're allowed to rely on the current rustc
191                // behaviour that options of bools will be one byte with
192                // no padding, so long as they're nested less than 254 deep.
193                let raw: u8 = unsafe { core::mem::transmute(*self) };
194                raw == 0
195            }
196        }
197    )+};
198}
199impl_for_optional_bool! {
200    Option<bool>,
201    Option<Option<bool>>,
202    Option<Option<Option<bool>>>,
203    // Could go further, but not worth the metadata overhead
204}
v6.2
  1// SPDX-License-Identifier: Apache-2.0 OR MIT
  2
 
 
  3use crate::boxed::Box;
  4
  5#[rustc_specialization_trait]
  6pub(super) unsafe trait IsZero {
  7    /// Whether this value's representation is all zeros
 
  8    fn is_zero(&self) -> bool;
  9}
 10
 11macro_rules! impl_is_zero {
 12    ($t:ty, $is_zero:expr) => {
 13        unsafe impl IsZero for $t {
 14            #[inline]
 15            fn is_zero(&self) -> bool {
 16                $is_zero(*self)
 17            }
 18        }
 19    };
 20}
 21
 
 22impl_is_zero!(i16, |x| x == 0);
 23impl_is_zero!(i32, |x| x == 0);
 24impl_is_zero!(i64, |x| x == 0);
 25impl_is_zero!(i128, |x| x == 0);
 26impl_is_zero!(isize, |x| x == 0);
 27
 
 28impl_is_zero!(u16, |x| x == 0);
 29impl_is_zero!(u32, |x| x == 0);
 30impl_is_zero!(u64, |x| x == 0);
 31impl_is_zero!(u128, |x| x == 0);
 32impl_is_zero!(usize, |x| x == 0);
 33
 34impl_is_zero!(bool, |x| x == false);
 35impl_is_zero!(char, |x| x == '\0');
 36
 37impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
 38impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
 39
 40unsafe impl<T> IsZero for *const T {
 41    #[inline]
 42    fn is_zero(&self) -> bool {
 43        (*self).is_null()
 44    }
 45}
 46
 47unsafe impl<T> IsZero for *mut T {
 48    #[inline]
 49    fn is_zero(&self) -> bool {
 50        (*self).is_null()
 51    }
 52}
 53
 54unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
 55    #[inline]
 56    fn is_zero(&self) -> bool {
 57        // Because this is generated as a runtime check, it's not obvious that
 58        // it's worth doing if the array is really long.  The threshold here
 59        // is largely arbitrary, but was picked because as of 2022-05-01 LLVM
 60        // can const-fold the check in `vec![[0; 32]; n]` but not in
 61        // `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b
 62        // Feel free to tweak if you have better evidence.
 63
 64        N <= 32 && self.iter().all(IsZero::is_zero)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 65    }
 66}
 67
 
 
 68// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
 69// For fat pointers, the bytes that would be the pointer metadata in the `Some`
 70// variant are padding in the `None` variant, so ignoring them and
 71// zero-initializing instead is ok.
 72// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
 73// `SpecFromElem`.
 74
 75unsafe impl<T: ?Sized> IsZero for Option<&T> {
 76    #[inline]
 77    fn is_zero(&self) -> bool {
 78        self.is_none()
 79    }
 80}
 81
 82unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
 83    #[inline]
 84    fn is_zero(&self) -> bool {
 85        self.is_none()
 86    }
 87}
 88
 89// `Option<num::NonZeroU32>` and similar have a representation guarantee that
 90// they're the same size as the corresponding `u32` type, as well as a guarantee
 91// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
 92// While the documentation officially makes it UB to transmute from `None`,
 93// we're the standard library so we can make extra inferences, and we know that
 94// the only niche available to represent `None` is the one that's all zeros.
 95
 96macro_rules! impl_is_zero_option_of_nonzero {
 97    ($($t:ident,)+) => {$(
 98        unsafe impl IsZero for Option<core::num::$t> {
 99            #[inline]
100            fn is_zero(&self) -> bool {
101                self.is_none()
102            }
103        }
104    )+};
105}
106
107impl_is_zero_option_of_nonzero!(
108    NonZeroU8,
109    NonZeroU16,
110    NonZeroU32,
111    NonZeroU64,
112    NonZeroU128,
113    NonZeroI8,
114    NonZeroI16,
115    NonZeroI32,
116    NonZeroI64,
117    NonZeroI128,
118    NonZeroUsize,
119    NonZeroIsize,
120);