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