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