/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 | 0 | fn remove_lowest_bit(self) -> Self { |
28 | 0 | BitMask(self.0 & (self.0 - 1)) |
29 | 0 | } Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::remove_lowest_bit Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::remove_lowest_bit |
30 | | |
31 | | /// Returns whether the `BitMask` has at least one set bit. |
32 | | #[inline] |
33 | 0 | pub(crate) fn any_bit_set(self) -> bool { |
34 | 0 | self.0 != 0 |
35 | 0 | } Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::any_bit_set Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::any_bit_set |
36 | | |
37 | | /// Returns the first set bit in the `BitMask`, if there is one. |
38 | | #[inline] |
39 | 0 | pub(crate) fn lowest_set_bit(self) -> Option<usize> { |
40 | 0 | if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { |
41 | 0 | Some(Self::nonzero_trailing_zeros(nonzero)) |
42 | | } else { |
43 | 0 | None |
44 | | } |
45 | 0 | } Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::lowest_set_bit Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::lowest_set_bit |
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 |
61 | | |
62 | | /// Same as above but takes a `NonZeroBitMaskWord`. |
63 | | #[inline] |
64 | 0 | fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { |
65 | 0 | 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 | 0 | nonzero.trailing_zeros() as usize / BITMASK_STRIDE |
71 | | } |
72 | 0 | } Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::nonzero_trailing_zeros Unexecuted instantiation: <hashbrown::control::bitmask::BitMask>::nonzero_trailing_zeros |
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 |
79 | | } |
80 | | |
81 | | impl IntoIterator for BitMask { |
82 | | type Item = usize; |
83 | | type IntoIter = BitMaskIter; |
84 | | |
85 | | #[inline] |
86 | 0 | 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 | 0 | BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) |
90 | 0 | } Unexecuted instantiation: <hashbrown::control::bitmask::BitMask as core::iter::traits::collect::IntoIterator>::into_iter Unexecuted instantiation: <hashbrown::control::bitmask::BitMask as core::iter::traits::collect::IntoIterator>::into_iter |
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 | 0 | fn next(&mut self) -> Option<usize> { |
103 | 0 | let bit = self.0.lowest_set_bit()?; |
104 | 0 | self.0 = self.0.remove_lowest_bit(); |
105 | 0 | Some(bit) |
106 | 0 | } Unexecuted instantiation: <hashbrown::control::bitmask::BitMaskIter as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <hashbrown::control::bitmask::BitMaskIter as core::iter::traits::iterator::Iterator>::next |
107 | | } |