/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hashbrown-0.17.1/src/control/bitmask.rs
Line | Count | Source |
1 | | use super::group::{BITMASK_ITER_MASK, BITMASK_STRIDE, BitMaskWord, NonZeroBitMaskWord}; |
2 | | |
3 | | /// A bit mask which contains the result of a `Match` operation on a `Group` and |
4 | | /// allows iterating through them. |
5 | | /// |
6 | | /// The bit mask is arranged so that low-order bits represent lower memory |
7 | | /// addresses for group match results. |
8 | | /// |
9 | | /// For implementation reasons, the bits in the set may be sparsely packed with |
10 | | /// groups of 8 bits representing one element. If any of these bits are non-zero |
11 | | /// then this element is considered to true in the mask. If this is the |
12 | | /// case, `BITMASK_STRIDE` will be 8 to indicate a divide-by-8 should be |
13 | | /// performed on counts/indices to normalize this difference. `BITMASK_MASK` is |
14 | | /// similarly a mask of all the actually-used bits. |
15 | | /// |
16 | | /// To iterate over a bit mask, it must be converted to a form where only 1 bit |
17 | | /// is set per element. This is done by applying `BITMASK_ITER_MASK` on the |
18 | | /// mask bits. |
19 | | #[derive(Copy, Clone)] |
20 | | pub(crate) struct BitMask(pub(crate) BitMaskWord); |
21 | | |
22 | | #[expect(clippy::use_self)] |
23 | | impl BitMask { |
24 | | /// Returns a new `BitMask` with the lowest bit removed. |
25 | | #[inline] |
26 | | #[must_use] |
27 | 561M | fn remove_lowest_bit(self) -> Self { |
28 | 561M | BitMask(self.0 & (self.0 - 1)) |
29 | 561M | } <hashbrown::control::bitmask::BitMask>::remove_lowest_bit Line | Count | Source | 27 | 225M | fn remove_lowest_bit(self) -> Self { | 28 | 225M | BitMask(self.0 & (self.0 - 1)) | 29 | 225M | } |
Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::remove_lowest_bit <hashbrown::control::bitmask::BitMask>::remove_lowest_bit Line | Count | Source | 27 | 336M | fn remove_lowest_bit(self) -> Self { | 28 | 336M | BitMask(self.0 & (self.0 - 1)) | 29 | 336M | } |
|
30 | | |
31 | | /// Returns whether the `BitMask` has at least one set bit. |
32 | | #[inline] |
33 | 4.02M | pub(crate) fn any_bit_set(self) -> bool { |
34 | 4.02M | self.0 != 0 |
35 | 4.02M | } <hashbrown::control::bitmask::BitMask>::any_bit_set Line | Count | Source | 33 | 1.89M | pub(crate) fn any_bit_set(self) -> bool { | 34 | 1.89M | self.0 != 0 | 35 | 1.89M | } |
Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::any_bit_set <hashbrown::control::bitmask::BitMask>::any_bit_set Line | Count | Source | 33 | 2.13M | pub(crate) fn any_bit_set(self) -> bool { | 34 | 2.13M | self.0 != 0 | 35 | 2.13M | } |
|
36 | | |
37 | | /// Returns the first set bit in the `BitMask`, if there is one. |
38 | | #[inline] |
39 | 572M | pub(crate) fn lowest_set_bit(self) -> Option<usize> { |
40 | 572M | if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { |
41 | 567M | Some(Self::nonzero_trailing_zeros(nonzero)) |
42 | | } else { |
43 | 4.60M | None |
44 | | } |
45 | 572M | } <hashbrown::control::bitmask::BitMask>::lowest_set_bit Line | Count | Source | 39 | 229M | pub(crate) fn lowest_set_bit(self) -> Option<usize> { | 40 | 229M | if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { | 41 | 227M | Some(Self::nonzero_trailing_zeros(nonzero)) | 42 | | } else { | 43 | 2.02M | None | 44 | | } | 45 | 229M | } |
Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::lowest_set_bit <hashbrown::control::bitmask::BitMask>::lowest_set_bit Line | Count | Source | 39 | 342M | pub(crate) fn lowest_set_bit(self) -> Option<usize> { | 40 | 342M | if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { | 41 | 339M | Some(Self::nonzero_trailing_zeros(nonzero)) | 42 | | } else { | 43 | 2.57M | None | 44 | | } | 45 | 342M | } |
|
46 | | |
47 | | /// Returns the number of trailing zeroes in the `BitMask`. |
48 | | #[inline] |
49 | 0 | pub(crate) fn trailing_zeros(self) -> usize { |
50 | | // ARM doesn't have a trailing_zeroes instruction, and instead uses |
51 | | // reverse_bits (RBIT) + leading_zeroes (CLZ). However older ARM |
52 | | // versions (pre-ARMv7) don't have RBIT and need to emulate it |
53 | | // instead. Since we only have 1 bit set in each byte on ARM, we can |
54 | | // use swap_bytes (REV) + leading_zeroes instead. |
55 | 0 | if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { |
56 | 0 | self.0.swap_bytes().leading_zeros() as usize / BITMASK_STRIDE |
57 | | } else { |
58 | 0 | self.0.trailing_zeros() as usize / BITMASK_STRIDE |
59 | | } |
60 | 0 | } Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::trailing_zeros Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::trailing_zeros Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::trailing_zeros |
61 | | |
62 | | /// Same as above but takes a `NonZeroBitMaskWord`. |
63 | | #[inline] |
64 | 567M | fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { |
65 | 567M | if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { |
66 | | // SAFETY: A byte-swapped non-zero value is still non-zero. |
67 | 0 | let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) }; |
68 | 0 | swapped.leading_zeros() as usize / BITMASK_STRIDE |
69 | | } else { |
70 | 567M | nonzero.trailing_zeros() as usize / BITMASK_STRIDE |
71 | | } |
72 | 567M | } <hashbrown::control::bitmask::BitMask>::nonzero_trailing_zeros Line | Count | Source | 64 | 227M | fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { | 65 | 227M | if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { | 66 | | // SAFETY: A byte-swapped non-zero value is still non-zero. | 67 | 0 | let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) }; | 68 | 0 | swapped.leading_zeros() as usize / BITMASK_STRIDE | 69 | | } else { | 70 | 227M | nonzero.trailing_zeros() as usize / BITMASK_STRIDE | 71 | | } | 72 | 227M | } |
Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::nonzero_trailing_zeros <hashbrown::control::bitmask::BitMask>::nonzero_trailing_zeros Line | Count | Source | 64 | 339M | fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { | 65 | 339M | if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { | 66 | | // SAFETY: A byte-swapped non-zero value is still non-zero. | 67 | 0 | let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) }; | 68 | 0 | swapped.leading_zeros() as usize / BITMASK_STRIDE | 69 | | } else { | 70 | 339M | nonzero.trailing_zeros() as usize / BITMASK_STRIDE | 71 | | } | 72 | 339M | } |
|
73 | | |
74 | | /// Returns the number of leading zeroes in the `BitMask`. |
75 | | #[inline] |
76 | 0 | pub(crate) fn leading_zeros(self) -> usize { |
77 | 0 | self.0.leading_zeros() as usize / BITMASK_STRIDE |
78 | 0 | } Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::leading_zeros Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::leading_zeros Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::leading_zeros |
79 | | } |
80 | | |
81 | | impl IntoIterator for BitMask { |
82 | | type Item = usize; |
83 | | type IntoIter = BitMaskIter; |
84 | | |
85 | | #[inline] |
86 | 563M | fn into_iter(self) -> BitMaskIter { |
87 | | // A BitMask only requires each element (group of bits) to be non-zero. |
88 | | // However for iteration we need each element to only contain 1 bit. |
89 | 563M | BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) |
90 | 563M | } <hashbrown::control::bitmask::BitMask as core::iter::traits::collect::IntoIterator>::into_iter Line | Count | Source | 86 | 226M | fn into_iter(self) -> BitMaskIter { | 87 | | // A BitMask only requires each element (group of bits) to be non-zero. | 88 | | // However for iteration we need each element to only contain 1 bit. | 89 | 226M | BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) | 90 | 226M | } |
Unexecuted instantiation: <hashbrown::control::bitmask::BitMask as core::iter::traits::collect::IntoIterator>::into_iter <hashbrown::control::bitmask::BitMask as core::iter::traits::collect::IntoIterator>::into_iter Line | Count | Source | 86 | 336M | fn into_iter(self) -> BitMaskIter { | 87 | | // A BitMask only requires each element (group of bits) to be non-zero. | 88 | | // However for iteration we need each element to only contain 1 bit. | 89 | 336M | BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) | 90 | 336M | } |
|
91 | | } |
92 | | |
93 | | /// Iterator over the contents of a `BitMask`, returning the indices of set |
94 | | /// bits. |
95 | | #[derive(Clone)] |
96 | | pub(crate) struct BitMaskIter(pub(crate) BitMask); |
97 | | |
98 | | impl Iterator for BitMaskIter { |
99 | | type Item = usize; |
100 | | |
101 | | #[inline] |
102 | 565M | fn next(&mut self) -> Option<usize> { |
103 | 565M | let bit = self.0.lowest_set_bit()?; |
104 | 561M | self.0 = self.0.remove_lowest_bit(); |
105 | 561M | Some(bit) |
106 | 565M | } <hashbrown::control::bitmask::BitMaskIter as core::iter::traits::iterator::Iterator>::next Line | Count | Source | 102 | 226M | fn next(&mut self) -> Option<usize> { | 103 | 226M | let bit = self.0.lowest_set_bit()?; | 104 | 225M | self.0 = self.0.remove_lowest_bit(); | 105 | 225M | Some(bit) | 106 | 226M | } |
Unexecuted instantiation: <hashbrown::control::bitmask::BitMaskIter as core::iter::traits::iterator::Iterator>::next <hashbrown::control::bitmask::BitMaskIter as core::iter::traits::iterator::Iterator>::next Line | Count | Source | 102 | 338M | fn next(&mut self) -> Option<usize> { | 103 | 338M | let bit = self.0.lowest_set_bit()?; | 104 | 336M | self.0 = self.0.remove_lowest_bit(); | 105 | 336M | Some(bit) | 106 | 338M | } |
|
107 | | } |