]> git.lizzy.rs Git - rust.git/blob - library/alloc/src/vec/is_zero.rs
Merge commit '63734fcdd718cca089f84c42f3a42c0096cfd431' into sync_cg_clif-2022-05-15
[rust.git] / library / alloc / src / vec / is_zero.rs
1 use crate::boxed::Box;
2
3 #[rustc_specialization_trait]
4 pub(super) unsafe trait IsZero {
5     /// Whether this value's representation is all zeros
6     fn is_zero(&self) -> bool;
7 }
8
9 macro_rules! impl_is_zero {
10     ($t:ty, $is_zero:expr) => {
11         unsafe impl IsZero for $t {
12             #[inline]
13             fn is_zero(&self) -> bool {
14                 $is_zero(*self)
15             }
16         }
17     };
18 }
19
20 impl_is_zero!(i16, |x| x == 0);
21 impl_is_zero!(i32, |x| x == 0);
22 impl_is_zero!(i64, |x| x == 0);
23 impl_is_zero!(i128, |x| x == 0);
24 impl_is_zero!(isize, |x| x == 0);
25
26 impl_is_zero!(u16, |x| x == 0);
27 impl_is_zero!(u32, |x| x == 0);
28 impl_is_zero!(u64, |x| x == 0);
29 impl_is_zero!(u128, |x| x == 0);
30 impl_is_zero!(usize, |x| x == 0);
31
32 impl_is_zero!(bool, |x| x == false);
33 impl_is_zero!(char, |x| x == '\0');
34
35 impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
36 impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
37
38 unsafe impl<T> IsZero for *const T {
39     #[inline]
40     fn is_zero(&self) -> bool {
41         (*self).is_null()
42     }
43 }
44
45 unsafe impl<T> IsZero for *mut T {
46     #[inline]
47     fn is_zero(&self) -> bool {
48         (*self).is_null()
49     }
50 }
51
52 unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
53     #[inline]
54     fn is_zero(&self) -> bool {
55         // Because this is generated as a runtime check, it's not obvious that
56         // it's worth doing if the array is really long.  The threshold here
57         // is largely arbitrary, but was picked because as of 2022-05-01 LLVM
58         // can const-fold the check in `vec![[0; 32]; n]` but not in
59         // `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b
60         // Feel free to tweak if you have better evidence.
61
62         N <= 32 && self.iter().all(IsZero::is_zero)
63     }
64 }
65
66 // `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
67 // For fat pointers, the bytes that would be the pointer metadata in the `Some`
68 // variant are padding in the `None` variant, so ignoring them and
69 // zero-initializing instead is ok.
70 // `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
71 // `SpecFromElem`.
72
73 unsafe impl<T: ?Sized> IsZero for Option<&T> {
74     #[inline]
75     fn is_zero(&self) -> bool {
76         self.is_none()
77     }
78 }
79
80 unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
81     #[inline]
82     fn is_zero(&self) -> bool {
83         self.is_none()
84     }
85 }
86
87 // `Option<num::NonZeroU32>` and similar have a representation guarantee that
88 // they're the same size as the corresponding `u32` type, as well as a guarantee
89 // that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
90 // While the documentation officially makes it UB to transmute from `None`,
91 // we're the standard library so we can make extra inferences, and we know that
92 // the only niche available to represent `None` is the one that's all zeros.
93
94 macro_rules! impl_is_zero_option_of_nonzero {
95     ($($t:ident,)+) => {$(
96         unsafe impl IsZero for Option<core::num::$t> {
97             #[inline]
98             fn is_zero(&self) -> bool {
99                 self.is_none()
100             }
101         }
102     )+};
103 }
104
105 impl_is_zero_option_of_nonzero!(
106     NonZeroU8,
107     NonZeroU16,
108     NonZeroU32,
109     NonZeroU64,
110     NonZeroU128,
111     NonZeroI8,
112     NonZeroI16,
113     NonZeroI32,
114     NonZeroI64,
115     NonZeroI128,
116     NonZeroUsize,
117     NonZeroIsize,
118 );