malachite_base/num/logic/
bit_scan.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::basic::signeds::PrimitiveSigned;
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::num::logic::traits::{BitScan, TrailingZeros};
12
13fn index_of_next_false_bit_unsigned<T: PrimitiveUnsigned>(x: T, start: u64) -> u64 {
14    if start >= T::WIDTH {
15        start
16    } else {
17        TrailingZeros::trailing_zeros(!(x | T::low_mask(start)))
18    }
19}
20
21fn index_of_next_true_bit_unsigned<T: PrimitiveUnsigned>(x: T, start: u64) -> Option<u64> {
22    if start >= T::WIDTH {
23        None
24    } else {
25        let index = TrailingZeros::trailing_zeros(x & !T::low_mask(start));
26        if index == T::WIDTH { None } else { Some(index) }
27    }
28}
29
30macro_rules! impl_bit_scan_unsigned {
31    ($t:ident) => {
32        impl BitScan for $t {
33            /// Given a number and a starting index, searches the number for the smallest index of a
34            /// `false` bit that is greater than or equal to the starting index.
35            ///
36            /// Since the number is unsigned and therefore has an implicit prefix of infinitely-many
37            /// zeros, this function always returns a value.
38            ///
39            /// Starting beyond the type's width is allowed; the result is the starting index.
40            ///
41            /// # Worst-case complexity
42            /// Constant time and additional memory.
43            ///
44            /// # Examples
45            /// See [here](super::bit_scan#index_of_next_false_bit).
46            #[inline]
47            fn index_of_next_false_bit(self, start: u64) -> Option<u64> {
48                Some(index_of_next_false_bit_unsigned(self, start))
49            }
50
51            /// Given a number and a starting index, searches the number for the smallest index of a
52            /// `true` bit that is greater than or equal to the starting index.
53            ///
54            /// If the starting index is greater than or equal to the type's width, the result is
55            /// `None` since there are no `true` bits past that point.
56            ///
57            /// # Worst-case complexity
58            /// Constant time and additional memory.
59            ///
60            /// # Examples
61            /// See [here](super::bit_scan#index_of_next_true_bit).
62            #[inline]
63            fn index_of_next_true_bit(self, start: u64) -> Option<u64> {
64                index_of_next_true_bit_unsigned(self, start)
65            }
66        }
67    };
68}
69apply_to_unsigneds!(impl_bit_scan_unsigned);
70
71fn index_of_next_false_bit_signed<T: PrimitiveSigned>(x: T, start: u64) -> Option<u64> {
72    if start >= T::WIDTH - 1 {
73        if x >= T::ZERO { Some(start) } else { None }
74    } else {
75        let index = TrailingZeros::trailing_zeros(!(x | T::low_mask(start)));
76        if index == T::WIDTH { None } else { Some(index) }
77    }
78}
79
80fn index_of_next_true_bit_signed<T: PrimitiveSigned>(x: T, start: u64) -> Option<u64> {
81    if start >= T::WIDTH - 1 {
82        if x >= T::ZERO { None } else { Some(start) }
83    } else {
84        let index = TrailingZeros::trailing_zeros(x & !T::low_mask(start));
85        if index == T::WIDTH { None } else { Some(index) }
86    }
87}
88
89macro_rules! impl_bit_scan_signed {
90    ($t:ident) => {
91        impl BitScan for $t {
92            /// Given a number and a starting index, searches the number for the smallest index of a
93            /// `false` bit that is greater than or equal to the starting index.
94            ///
95            /// If the starting index is greater than or equal to the type's width, then the result
96            /// depends on whether the number is negative. If it is, then the result is `None` since
97            /// there are no `false` bits past that point. If the number is non-negative, then the
98            /// result is the starting index.
99            ///
100            /// # Worst-case complexity
101            /// Constant time and additional memory.
102            ///
103            /// # Examples
104            /// See [here](super::bit_scan#index_of_next_false_bit).
105            #[inline]
106            fn index_of_next_false_bit(self, start: u64) -> Option<u64> {
107                index_of_next_false_bit_signed(self, start)
108            }
109
110            /// Given a number and a starting index, searches the number for the smallest index of a
111            /// `true` bit that is greater than or equal to the starting index.
112            ///
113            /// If the starting index is greater than or equal to the type's width, then the result
114            /// depends on whether the number is non-negative. If it is, then the result is `None`
115            /// since there are no `true` bits past that point. If the number is negative, then the
116            /// result is the starting index.
117            ///
118            /// # Worst-case complexity
119            /// Constant time and additional memory.
120            ///
121            /// # Examples
122            /// See [here](super::bit_scan#index_of_next_true_bit).
123            #[inline]
124            fn index_of_next_true_bit(self, start: u64) -> Option<u64> {
125                index_of_next_true_bit_signed(self, start)
126            }
127        }
128    };
129}
130apply_to_signeds!(impl_bit_scan_signed);