malachite_nz/integer/logic/bit_block_access.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::integer::Integer;
10use crate::integer::conversion::to_twos_complement_limbs::limbs_twos_complement_in_place;
11use crate::natural::InnerNatural::{Large, Small};
12use crate::natural::Natural;
13use crate::natural::arithmetic::add::limbs_vec_add_limb_in_place;
14use crate::natural::arithmetic::mod_power_of_2::limbs_vec_mod_power_of_2_in_place;
15use crate::natural::arithmetic::shr::limbs_slice_shr_in_place;
16use crate::natural::arithmetic::sub::limbs_sub_limb_in_place;
17use crate::natural::logic::bit_block_access::limbs_assign_bits_helper;
18use crate::natural::logic::not::limbs_not_in_place;
19use crate::natural::logic::trailing_zeros::limbs_trailing_zeros;
20use crate::platform::Limb;
21use alloc::vec::Vec;
22use malachite_base::num::arithmetic::traits::{ModPowerOf2, ShrRound};
23use malachite_base::num::basic::integers::PrimitiveInt;
24use malachite_base::num::conversion::traits::ExactFrom;
25use malachite_base::num::logic::traits::{BitBlockAccess, LeadingZeros, TrailingZeros};
26use malachite_base::rounding_modes::RoundingMode::*;
27use malachite_base::vecs::vec_delete_left;
28
29// Returns the limbs obtained by taking a slice of bits beginning at index `start` of the negative
30// of `limb` and ending at index `end - 1`. `start` must be less than or equal to `end`, but apart
31// from that there are no restrictions on the index values. If they index beyond the physical size
32// of the input limbs, the function interprets them as pointing to `true` bits. `x` must be
33// positive.
34//
35// # Worst-case complexity
36// $T(n) = O(n)$
37//
38// $M(n) = O(n)$
39//
40// where $T$ is time, $M$ is additional memory and $n$ is `end`.
41//
42// # Panics
43// Panics if `start > end`.
44pub_test! {limbs_neg_limb_get_bits(x: Limb, start: u64, end: u64) -> Vec<Limb> {
45 assert!(start <= end);
46 let trailing_zeros = TrailingZeros::trailing_zeros(x);
47 if trailing_zeros >= end {
48 return Vec::new();
49 }
50 let bit_len = end - start;
51 let mut out = if start >= Limb::WIDTH {
52 vec![
53 Limb::MAX;
54 usize::exact_from(bit_len.shr_round(Limb::LOG_WIDTH, Ceiling).0)
55 ]
56 } else {
57 let mut out = vec![x >> start];
58 out.resize(usize::exact_from(end >> Limb::LOG_WIDTH) + 1, 0);
59 if trailing_zeros >= start {
60 limbs_twos_complement_in_place(&mut out);
61 } else {
62 limbs_not_in_place(&mut out);
63 }
64 out
65 };
66 limbs_vec_mod_power_of_2_in_place(&mut out, bit_len);
67 out
68}}
69
70// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, returns the
71// limbs obtained by taking a slice of bits beginning at index `start` of the negative of the
72// `Natural` and ending at index `end - 1`. `start` must be less than or equal to `end`, but apart
73// from that there are no restrictions on the index values. If they index beyond the physical size
74// of the input limbs, the function interprets them as pointing to `true` bits. The input slice
75// cannot only contain zeros.
76//
77// # Worst-case complexity
78// $T(n) = O(n)$
79//
80// $M(n) = O(n)$
81//
82// where $T$ is time, $M$ is additional memory and $n$ is `max(xs.len(), end * Limb::WIDTH)`.
83//
84// # Panics
85// Panics if `start > end`.
86pub_test! {limbs_slice_neg_get_bits(xs: &[Limb], start: u64, end: u64) -> Vec<Limb> {
87 assert!(start <= end);
88 let trailing_zeros = limbs_trailing_zeros(xs);
89 if trailing_zeros >= end {
90 return Vec::new();
91 }
92 let start_i = usize::exact_from(start >> Limb::LOG_WIDTH);
93 let len = xs.len();
94 let bit_len = end - start;
95 if start_i >= len {
96 let mut out =
97 vec![
98 Limb::MAX;
99 usize::exact_from(bit_len.shr_round(Limb::LOG_WIDTH, Ceiling).0)
100 ];
101 limbs_vec_mod_power_of_2_in_place(&mut out, bit_len);
102 return out;
103 }
104 let end_i = usize::exact_from(end >> Limb::LOG_WIDTH) + 1;
105 let mut out = (if end_i >= len {
106 &xs[start_i..]
107 } else {
108 &xs[start_i..end_i]
109 })
110 .to_vec();
111 let offset = start & Limb::WIDTH_MASK;
112 if offset != 0 {
113 limbs_slice_shr_in_place(&mut out, offset);
114 }
115 out.resize(end_i - start_i, 0);
116 if trailing_zeros >= start {
117 limbs_twos_complement_in_place(&mut out);
118 } else {
119 limbs_not_in_place(&mut out);
120 }
121 limbs_vec_mod_power_of_2_in_place(&mut out, bit_len);
122 out
123}}
124
125// Interpreting a `Vec` of `Limb`s as the limbs (in ascending order) of a `Natural`, returns the
126// limbs obtained by taking a slice of bits beginning at index `start` of the negative of the
127// `Natural` and ending at index `end - 1`. `start` must be less than or equal to `end`, but apart
128// from that there are no restrictions on the index values. If they index beyond the physical size
129// of the input limbs, the function interprets them as pointing to `true` bits. The input slice
130// cannot only contain zeros.
131//
132// # Worst-case complexity
133// $T(n) = O(n)$
134//
135// $M(n) = O(n)$
136//
137// where $T$ is time, $M$ is additional memory and $n$ is `max(xs.len(), end * Limb::WIDTH)`.
138//
139// # Panics
140// Panics if `start > end`.
141pub_test! {limbs_vec_neg_get_bits(mut xs: Vec<Limb>, start: u64, end: u64) -> Vec<Limb> {
142 assert!(start <= end);
143 let trailing_zeros = limbs_trailing_zeros(&xs);
144 if trailing_zeros >= end {
145 return Vec::new();
146 }
147 let start_i = usize::exact_from(start >> Limb::LOG_WIDTH);
148 let len = xs.len();
149 let bit_len = end - start;
150 if start_i >= len {
151 xs = vec![
152 Limb::MAX;
153 usize::exact_from(bit_len.shr_round(Limb::LOG_WIDTH, Ceiling).0)
154 ];
155 limbs_vec_mod_power_of_2_in_place(&mut xs, bit_len);
156 return xs;
157 }
158 let end_i = usize::exact_from(end >> Limb::LOG_WIDTH) + 1;
159 xs.truncate(end_i);
160 vec_delete_left(&mut xs, start_i);
161 let offset = start & Limb::WIDTH_MASK;
162 if offset != 0 {
163 limbs_slice_shr_in_place(&mut xs, offset);
164 }
165 xs.resize(end_i - start_i, 0);
166 if trailing_zeros >= start {
167 limbs_twos_complement_in_place(&mut xs);
168 } else {
169 limbs_not_in_place(&mut xs);
170 }
171 limbs_vec_mod_power_of_2_in_place(&mut xs, bit_len);
172 xs
173}}
174
175// Interpreting a `Vec` of `Limb`s as the limbs (in ascending order) of a `Natural` n, writes the
176// limbs of `bits` into the limbs of -n, starting at bit `start` of -n (inclusive) and ending at bit
177// `end` of -n (exclusive). The bit indices do not need to be aligned with any limb boundaries. If
178// `bits` has more than `end` - `start` bits, only the first `end` - `start` bits are written. If
179// `bits` has fewer than `end` - `start` bits, the remaining written bits are one. `xs` may be
180// extended to accommodate the new bits. `start` must be smaller than `end`, and `xs` cannot only
181// contain zeros.
182//
183// # Worst-case complexity
184// $T(n) = O(n)$
185//
186// $M(m) = O(m)$
187//
188// where $T$ is time, $M$ is additional memory, $n$ is `max(n / 2 ^ Limb::WIDTH, m)`, and $m$ is
189// `end`.
190//
191// # Panics
192// Panics if `start >= end` or `xs` only contains zeros.
193pub_test! {limbs_neg_assign_bits(xs: &mut Vec<Limb>, start: u64, end: u64, bits: &[Limb]) {
194 assert!(start < end);
195 assert!(!limbs_sub_limb_in_place(xs, 1));
196 limbs_assign_bits_helper(xs, start, end, bits, true);
197 limbs_vec_add_limb_in_place(xs, 1);
198}}
199
200impl Natural {
201 fn neg_get_bits(&self, start: u64, end: u64) -> Natural {
202 Natural::from_owned_limbs_asc(match self {
203 Natural(Small(small)) => limbs_neg_limb_get_bits(*small, start, end),
204 Natural(Large(limbs)) => limbs_slice_neg_get_bits(limbs, start, end),
205 })
206 }
207
208 fn neg_get_bits_owned(self, start: u64, end: u64) -> Natural {
209 Natural::from_owned_limbs_asc(match self {
210 Natural(Small(small)) => limbs_neg_limb_get_bits(small, start, end),
211 Natural(Large(limbs)) => limbs_vec_neg_get_bits(limbs, start, end),
212 })
213 }
214
215 fn neg_assign_bits(&mut self, start: u64, end: u64, bits: &Natural) {
216 if start == end {
217 return;
218 }
219 let bits_width = end - start;
220 if bits_width <= Limb::WIDTH {
221 if let (&mut Natural(Small(ref mut small_self)), &Natural(Small(small_bits))) =
222 (&mut *self, bits)
223 {
224 let small_bits = (!small_bits).mod_power_of_2(bits_width);
225 if small_bits == 0 || LeadingZeros::leading_zeros(small_bits) >= start {
226 let mut new_small_self = *small_self - 1;
227 new_small_self.assign_bits(start, end, &small_bits);
228 let (sum, overflow) = new_small_self.overflowing_add(1);
229 if !overflow {
230 *small_self = sum;
231 return;
232 }
233 }
234 }
235 }
236 let limbs = self.promote_in_place();
237 match bits {
238 Natural(Small(small_bits)) => limbs_neg_assign_bits(limbs, start, end, &[*small_bits]),
239 Natural(Large(bits_limbs)) => limbs_neg_assign_bits(limbs, start, end, bits_limbs),
240 }
241 self.trim();
242 }
243}
244
245impl BitBlockAccess for Integer {
246 type Bits = Natural;
247
248 /// Extracts a block of adjacent two's complement bits from an [`Integer`], taking the
249 /// [`Integer`] by reference.
250 ///
251 /// The first index is `start` and last index is `end - 1`.
252 ///
253 /// Let $n$ be `self`, and let $p$ and $q$ be `start` and `end`, respectively.
254 ///
255 /// If $n \geq 0$, let
256 /// $$
257 /// n = \sum_{i=0}^\infty 2^{b_i};
258 /// $$
259 /// but if $n < 0$, let
260 /// $$
261 /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
262 /// $$
263 /// where for all $i$, $b_i\in \\{0, 1\\}$. Then
264 /// $$
265 /// f(n, p, q) = \sum_{i=p}^{q-1} 2^{b_{i-p}}.
266 /// $$
267 ///
268 /// # Worst-case complexity
269 /// $T(n) = O(n)$
270 ///
271 /// $M(n) = O(n)$
272 ///
273 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(), end)`.
274 ///
275 /// # Panics
276 /// Panics if `start > end`.
277 ///
278 /// # Examples
279 /// ```
280 /// use core::str::FromStr;
281 /// use malachite_base::num::basic::traits::Zero;
282 /// use malachite_base::num::logic::traits::BitBlockAccess;
283 /// use malachite_nz::integer::Integer;
284 /// use malachite_nz::natural::Natural;
285 ///
286 /// assert_eq!(
287 /// (-Natural::from(0xabcdef0112345678u64)).get_bits(16, 48),
288 /// Natural::from(0x10feedcbu32)
289 /// );
290 /// assert_eq!(
291 /// Integer::from(0xabcdef0112345678u64).get_bits(4, 16),
292 /// Natural::from(0x567u32)
293 /// );
294 /// assert_eq!(
295 /// (-Natural::from(0xabcdef0112345678u64)).get_bits(0, 100),
296 /// Natural::from_str("1267650600215849587758112418184").unwrap()
297 /// );
298 /// assert_eq!(
299 /// Integer::from(0xabcdef0112345678u64).get_bits(10, 10),
300 /// Natural::ZERO
301 /// );
302 /// ```
303 fn get_bits(&self, start: u64, end: u64) -> Natural {
304 if self.sign {
305 self.abs.get_bits(start, end)
306 } else {
307 self.abs.neg_get_bits(start, end)
308 }
309 }
310
311 /// Extracts a block of adjacent two's complement bits from an [`Integer`], taking the
312 /// [`Integer`] by value.
313 ///
314 /// The first index is `start` and last index is `end - 1`.
315 ///
316 /// Let $n$ be `self`, and let $p$ and $q$ be `start` and `end`, respectively.
317 ///
318 /// If $n \geq 0$, let
319 /// $$
320 /// n = \sum_{i=0}^\infty 2^{b_i};
321 /// $$
322 /// but if $n < 0$, let
323 /// $$
324 /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
325 /// $$
326 /// where for all $i$, $b_i\in \\{0, 1\\}$. Then
327 /// $$
328 /// f(n, p, q) = \sum_{i=p}^{q-1} 2^{b_{i-p}}.
329 /// $$
330 ///
331 /// # Worst-case complexity
332 /// $T(n) = O(n)$
333 ///
334 /// $M(n) = O(n)$
335 ///
336 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(), end)`.
337 ///
338 /// # Panics
339 /// Panics if `start > end`.
340 ///
341 /// # Examples
342 /// ```
343 /// use core::str::FromStr;
344 /// use malachite_base::num::basic::traits::Zero;
345 /// use malachite_base::num::logic::traits::BitBlockAccess;
346 /// use malachite_nz::integer::Integer;
347 /// use malachite_nz::natural::Natural;
348 ///
349 /// assert_eq!(
350 /// (-Natural::from(0xabcdef0112345678u64)).get_bits_owned(16, 48),
351 /// Natural::from(0x10feedcbu32)
352 /// );
353 /// assert_eq!(
354 /// Integer::from(0xabcdef0112345678u64).get_bits_owned(4, 16),
355 /// Natural::from(0x567u32)
356 /// );
357 /// assert_eq!(
358 /// (-Natural::from(0xabcdef0112345678u64)).get_bits_owned(0, 100),
359 /// Natural::from_str("1267650600215849587758112418184").unwrap()
360 /// );
361 /// assert_eq!(
362 /// Integer::from(0xabcdef0112345678u64).get_bits_owned(10, 10),
363 /// Natural::ZERO
364 /// );
365 /// ```
366 fn get_bits_owned(self, start: u64, end: u64) -> Natural {
367 if self.sign {
368 self.abs.get_bits_owned(start, end)
369 } else {
370 self.abs.neg_get_bits_owned(start, end)
371 }
372 }
373
374 /// Replaces a block of adjacent two's complement bits in an [`Integer`] with other bits.
375 ///
376 /// The least-significant `end - start` bits of `bits` are assigned to bits `start` through `end
377 /// - 1`, inclusive, of `self`.
378 ///
379 /// Let $n$ be `self` and let $m$ be `bits`, and let $p$ and $q$ be `start` and `end`,
380 /// respectively.
381 ///
382 /// Let
383 /// $$
384 /// m = \sum_{i=0}^k 2^{d_i},
385 /// $$
386 /// where for all $i$, $d_i\in \\{0, 1\\}$.
387 ///
388 /// If $n \geq 0$, let
389 /// $$
390 /// n = \sum_{i=0}^\infty 2^{b_i};
391 /// $$
392 /// but if $n < 0$, let
393 /// $$
394 /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
395 /// $$
396 /// where for all $i$, $b_i\in \\{0, 1\\}$. Then
397 /// $$
398 /// n \gets \sum_{i=0}^\infty 2^{c_i},
399 /// $$
400 /// where
401 /// $$
402 /// \\{c_0, c_1, c_2, \ldots \\} =
403 /// \\{b_0, b_1, b_2, \ldots, b_{p-1}, d_0, d_1, \ldots, d_{p-q-1}, b_q, b_{q+1}, \ldots \\}.
404 /// $$
405 ///
406 /// # Worst-case complexity
407 /// $T(n) = O(n)$
408 ///
409 /// $M(m) = O(m)$
410 ///
411 /// where $T$ is time, $M$ is additional memory, $n$ is `max(self.significant_bits(), end)`, and
412 /// $m$ is `self.significant_bits()`.
413 ///
414 /// # Panics
415 /// Panics if `start > end`.
416 ///
417 /// # Examples
418 /// ```
419 /// use malachite_base::num::logic::traits::BitBlockAccess;
420 /// use malachite_nz::integer::Integer;
421 /// use malachite_nz::natural::Natural;
422 ///
423 /// let mut n = Integer::from(123);
424 /// n.assign_bits(5, 7, &Natural::from(456u32));
425 /// assert_eq!(n.to_string(), "27");
426 ///
427 /// let mut n = Integer::from(-123);
428 /// n.assign_bits(64, 128, &Natural::from(456u32));
429 /// assert_eq!(n.to_string(), "-340282366920938455033212565746503123067");
430 ///
431 /// let mut n = Integer::from(-123);
432 /// n.assign_bits(80, 100, &Natural::from(456u32));
433 /// assert_eq!(n.to_string(), "-1267098121128665515963862483067");
434 /// ```
435 fn assign_bits(&mut self, start: u64, end: u64, bits: &Natural) {
436 if self.sign {
437 self.abs.assign_bits(start, end, bits);
438 } else {
439 self.abs.neg_assign_bits(start, end, bits);
440 }
441 }
442}