malachite_nz/integer/logic/bit_scan.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5// Copyright © 2000-2002, 2004, 2012, 2015 Free Software Foundation, Inc.
6//
7// This file is part of Malachite.
8//
9// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
10// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
11// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
12
13use crate::integer::Integer;
14use crate::natural::InnerNatural::{Large, Small};
15use crate::natural::logic::bit_scan::{
16 limbs_index_of_next_false_bit, limbs_index_of_next_true_bit,
17};
18use crate::natural::{Natural, bit_to_limb_count_floor, limb_to_bit_count};
19use crate::platform::Limb;
20use core::cmp::Ordering::*;
21use malachite_base::num::basic::integers::PrimitiveInt;
22use malachite_base::num::logic::traits::{BitScan, LowMask, TrailingZeros};
23use malachite_base::slices::slice_leading_zeros;
24
25// Interpreting a slice of `Limb`s as the limbs (in ascending order) of the negative of an
26// `Integer`, finds the lowest index greater than or equal to `starting_index` at which the
27// `Integer` has a `false` bit. If the starting index is too large and there are no more `false`
28// bits above it, `None` is returned.
29//
30// # Worst-case complexity
31// $T(n) = O(n)$
32//
33// $M(n) = O(1)$
34//
35// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
36//
37// This is equivalent to `mpz_scan0` from `mpz/scan0.c`, GMP 6.2.1.
38private_test_fn! {limbs_index_of_next_false_bit_neg(
39 xs: &[Limb],
40 mut starting_index: u64,
41) -> Option<u64> {
42 let n = xs.len();
43 let i = slice_leading_zeros(xs);
44 assert!(i < n);
45 let starting_limb_index = bit_to_limb_count_floor(starting_index);
46 if starting_limb_index >= n {
47 return None;
48 }
49 let after_boundary_offset = limb_to_bit_count(i + 1);
50 match starting_limb_index.cmp(&i) {
51 Equal => {
52 let within_limb_index = starting_index & Limb::WIDTH_MASK;
53 if let Some(result) = xs[i]
54 .wrapping_neg()
55 .index_of_next_false_bit(within_limb_index)
56 {
57 if result < Limb::WIDTH {
58 return Some(limb_to_bit_count(i) + result);
59 }
60 starting_index = 0;
61 }
62 }
63 Less => {
64 return Some(starting_index);
65 }
66 Greater => {
67 starting_index -= after_boundary_offset;
68 }
69 }
70 limbs_index_of_next_true_bit(&xs[i + 1..], starting_index)
71 .map(|result| result + after_boundary_offset)
72}}
73
74// Interpreting a slice of `Limb`s as the limbs (in ascending order) of the negative of an
75// `Integer`, finds the lowest index greater than or equal to `starting_index` at which the
76// `Integer` has a `true` bit.
77//
78// # Worst-case complexity
79// $T(n) = O(n)$
80//
81// $M(n) = O(1)$
82//
83// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
84//
85// This is equivalent to `mpz_scan1` from `mpz/scan1.c`, GMP 6.2.1.
86private_test_fn! {limbs_index_of_next_true_bit_neg(xs: &[Limb], mut starting_index: u64) -> u64 {
87 let n = xs.len();
88 let i = slice_leading_zeros(xs);
89 assert!(i < n);
90 let mut starting_limb_index = bit_to_limb_count_floor(starting_index);
91 if starting_limb_index >= n {
92 return starting_index;
93 }
94 let after_boundary_offset = limb_to_bit_count(i + 1);
95 if starting_limb_index < i {
96 starting_index = limb_to_bit_count(i);
97 starting_limb_index = i;
98 }
99 if starting_limb_index == i {
100 let within_limb_index = starting_index & Limb::WIDTH_MASK;
101 if let Some(result) = xs[i]
102 .wrapping_neg()
103 .index_of_next_true_bit(within_limb_index)
104 {
105 return limb_to_bit_count(i) + result;
106 }
107 starting_index = 0;
108 } else {
109 starting_index -= after_boundary_offset;
110 }
111 limbs_index_of_next_false_bit(&xs[i + 1..], starting_index) + after_boundary_offset
112}}
113
114impl Natural {
115 // self != 0
116 fn index_of_next_false_bit_neg(&self, starting_index: u64) -> Option<u64> {
117 match self {
118 Self(Small(small)) => {
119 if starting_index >= Limb::WIDTH {
120 None
121 } else {
122 let index = TrailingZeros::trailing_zeros(
123 (small - 1) & !Limb::low_mask(starting_index),
124 );
125 if index == Limb::WIDTH {
126 None
127 } else {
128 Some(index)
129 }
130 }
131 }
132 Self(Large(limbs)) => limbs_index_of_next_false_bit_neg(limbs, starting_index),
133 }
134 }
135
136 // self != 0
137 fn index_of_next_true_bit_neg(&self, starting_index: u64) -> u64 {
138 match self {
139 Self(Small(small)) => {
140 if starting_index >= Limb::WIDTH {
141 starting_index
142 } else {
143 TrailingZeros::trailing_zeros(!((small - 1) | Limb::low_mask(starting_index)))
144 }
145 }
146 Self(Large(limbs)) => limbs_index_of_next_true_bit_neg(limbs, starting_index),
147 }
148 }
149}
150
151impl BitScan for &Integer {
152 /// Given an [`Integer`] and a starting index, searches the [`Integer`] for the smallest index
153 /// of a `false` bit that is greater than or equal to the starting index.
154 ///
155 /// If the [`Integer]` is negative, and the starting index is too large and there are no more
156 /// `false` bits above it, `None` is returned.
157 ///
158 /// # Worst-case complexity
159 /// $T(n) = O(n)$
160 ///
161 /// $M(n) = O(1)$
162 ///
163 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
164 ///
165 /// # Examples
166 /// ```
167 /// use malachite_base::num::logic::traits::BitScan;
168 /// use malachite_nz::integer::Integer;
169 ///
170 /// assert_eq!(
171 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(0),
172 /// Some(0)
173 /// );
174 /// assert_eq!(
175 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(20),
176 /// Some(20)
177 /// );
178 /// assert_eq!(
179 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(31),
180 /// Some(31)
181 /// );
182 /// assert_eq!(
183 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(32),
184 /// Some(34)
185 /// );
186 /// assert_eq!(
187 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(33),
188 /// Some(34)
189 /// );
190 /// assert_eq!(
191 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(34),
192 /// Some(34)
193 /// );
194 /// assert_eq!(
195 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(35),
196 /// None
197 /// );
198 /// assert_eq!(
199 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(100),
200 /// None
201 /// );
202 /// ```
203 fn index_of_next_false_bit(self, starting_index: u64) -> Option<u64> {
204 if self.sign {
205 self.abs.index_of_next_false_bit(starting_index)
206 } else {
207 self.abs.index_of_next_false_bit_neg(starting_index)
208 }
209 }
210
211 /// Given an [`Integer`] and a starting index, searches the [`Integer`] for the smallest index
212 /// of a `true` bit that is greater than or equal to the starting index.
213 ///
214 /// If the [`Integer`] is non-negative, and the starting index is too large and there are no
215 /// more `true` bits above it, `None` is returned.
216 ///
217 /// # Worst-case complexity
218 /// $T(n) = O(n)$
219 ///
220 /// $M(n) = O(1)$
221 ///
222 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
223 ///
224 /// # Examples
225 /// ```
226 /// use malachite_base::num::logic::traits::BitScan;
227 /// use malachite_nz::integer::Integer;
228 ///
229 /// assert_eq!(
230 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(0),
231 /// Some(32)
232 /// );
233 /// assert_eq!(
234 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(20),
235 /// Some(32)
236 /// );
237 /// assert_eq!(
238 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(31),
239 /// Some(32)
240 /// );
241 /// assert_eq!(
242 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(32),
243 /// Some(32)
244 /// );
245 /// assert_eq!(
246 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(33),
247 /// Some(33)
248 /// );
249 /// assert_eq!(
250 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(34),
251 /// Some(35)
252 /// );
253 /// assert_eq!(
254 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(35),
255 /// Some(35)
256 /// );
257 /// assert_eq!(
258 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(36),
259 /// Some(36)
260 /// );
261 /// assert_eq!(
262 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(100),
263 /// Some(100)
264 /// );
265 /// ```
266 fn index_of_next_true_bit(self, starting_index: u64) -> Option<u64> {
267 if self.sign {
268 self.abs.index_of_next_true_bit(starting_index)
269 } else {
270 Some(self.abs.index_of_next_true_bit_neg(starting_index))
271 }
272 }
273}