]> git.proxmox.com Git - rustc.git/blame - library/alloc/src/vec/is_zero.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / library / alloc / src / vec / is_zero.rs
CommitLineData
f2b60f7d
FG
1use core::num::{Saturating, Wrapping};
2
5869c6ff
XL
3use crate::boxed::Box;
4
5#[rustc_specialization_trait]
6pub(super) unsafe trait IsZero {
04454e1e 7 /// Whether this value's representation is all zeros
5869c6ff
XL
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
064997fb 22impl_is_zero!(i8, |x| x == 0); // It is needed to impl for arrays and tuples of i8.
5869c6ff
XL
23impl_is_zero!(i16, |x| x == 0);
24impl_is_zero!(i32, |x| x == 0);
25impl_is_zero!(i64, |x| x == 0);
26impl_is_zero!(i128, |x| x == 0);
27impl_is_zero!(isize, |x| x == 0);
28
064997fb 29impl_is_zero!(u8, |x| x == 0); // It is needed to impl for arrays and tuples of u8.
5869c6ff
XL
30impl_is_zero!(u16, |x| x == 0);
31impl_is_zero!(u32, |x| x == 0);
32impl_is_zero!(u64, |x| x == 0);
33impl_is_zero!(u128, |x| x == 0);
34impl_is_zero!(usize, |x| x == 0);
35
36impl_is_zero!(bool, |x| x == false);
37impl_is_zero!(char, |x| x == '\0');
38
39impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
40impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
41
42unsafe impl<T> IsZero for *const T {
43 #[inline]
44 fn is_zero(&self) -> bool {
45 (*self).is_null()
46 }
47}
48
49unsafe impl<T> IsZero for *mut T {
50 #[inline]
51 fn is_zero(&self) -> bool {
52 (*self).is_null()
53 }
54}
55
04454e1e
FG
56unsafe 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.
71macro_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
94impl_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
103unsafe impl<T: ?Sized> IsZero for Option<&T> {
104 #[inline]
105 fn is_zero(&self) -> bool {
106 self.is_none()
107 }
108}
109
110unsafe 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
124macro_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
135impl_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
150unsafe impl<T: IsZero> IsZero for Wrapping<T> {
151 #[inline]
152 fn is_zero(&self) -> bool {
153 self.0.is_zero()
154 }
155}
156
157unsafe 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
164macro_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}
179impl_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}