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