1 | #[cfg (feature = "unstable-public-internals" )] |
2 | pub use implementation::trailing_zeros; |
3 | #[cfg (not(feature = "unstable-public-internals" ))] |
4 | pub(crate) use implementation::trailing_zeros; |
5 | |
6 | mod implementation { |
7 | use crate::int::{CastFrom, Int}; |
8 | |
9 | /// Returns number of trailing binary zeros in `x`. |
10 | #[allow (dead_code)] |
11 | pub fn trailing_zeros<I: Int>(x: I) -> usize |
12 | where |
13 | u32: CastFrom<I>, |
14 | u16: CastFrom<I>, |
15 | u8: CastFrom<I>, |
16 | { |
17 | let mut x = x; |
18 | let mut r: u32 = 0; |
19 | let mut t: u32; |
20 | |
21 | const { assert!(I::BITS <= 64) }; |
22 | if I::BITS >= 64 { |
23 | r += ((u32::cast_from_lossy(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 |
24 | x >>= r; // remove 32 zero bits |
25 | } |
26 | |
27 | if I::BITS >= 32 { |
28 | t = ((u16::cast_from_lossy(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 |
29 | r += t; |
30 | x >>= t; // x = [0 - 0xFFFF] + higher garbage bits |
31 | } |
32 | |
33 | const { assert!(I::BITS >= 16) }; |
34 | t = ((u8::cast_from_lossy(x) == 0) as u32) << 3; |
35 | x >>= t; // x = [0 - 0xFF] + higher garbage bits |
36 | r += t; |
37 | |
38 | let mut x: u8 = x.cast_lossy(); |
39 | |
40 | t = (((x & 0x0F) == 0) as u32) << 2; |
41 | x >>= t; // x = [0 - 0xF] + higher garbage bits |
42 | r += t; |
43 | |
44 | t = (((x & 0x3) == 0) as u32) << 1; |
45 | x >>= t; // x = [0 - 0x3] + higher garbage bits |
46 | r += t; |
47 | |
48 | x &= 3; |
49 | |
50 | r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) |
51 | } |
52 | } |
53 | |
54 | intrinsics! { |
55 | /// Returns the number of trailing binary zeros in `x` (32 bit version). |
56 | pub extern "C" fn __ctzsi2(x: u32) -> usize { |
57 | trailing_zeros(x) |
58 | } |
59 | |
60 | /// Returns the number of trailing binary zeros in `x` (64 bit version). |
61 | pub extern "C" fn __ctzdi2(x: u64) -> usize { |
62 | trailing_zeros(x) |
63 | } |
64 | |
65 | /// Returns the number of trailing binary zeros in `x` (128 bit version). |
66 | pub extern "C" fn __ctzti2(x: u128) -> usize { |
67 | let lo = x as u64; |
68 | if lo == 0 { |
69 | 64 + __ctzdi2((x >> 64) as u64) |
70 | } else { |
71 | __ctzdi2(lo) |
72 | } |
73 | } |
74 | } |
75 | |