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