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::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`.
42pub_test! {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`.
84pub_test! {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`.
135pub_test! {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(n / 2 ^ Limb::WIDTH, m)`, and $m$ is
180// `end`.
181//
182// # Panics
183// Panics if `start >= end` or `xs` only contains zeros.
184pub_test! {limbs_neg_assign_bits(xs: &mut Vec<Limb>, start: u64, end: u64, bits: &[Limb]) {
185 assert!(start < end);
186 assert!(!limbs_sub_limb_in_place(xs, 1));
187 limbs_assign_bits_helper(xs, start, end, bits, true);
188 limbs_vec_add_limb_in_place(xs, 1);
189}}
190
191impl Natural {
192 fn neg_get_bits(&self, start: u64, end: u64) -> Self {
193 Self::from_owned_limbs_asc(match self {
194 Self(Small(small)) => limbs_neg_limb_get_bits(*small, start, end),
195 Self(Large(limbs)) => limbs_slice_neg_get_bits(limbs, start, end),
196 })
197 }
198
199 fn neg_get_bits_owned(self, start: u64, end: u64) -> Self {
200 Self::from_owned_limbs_asc(match self {
201 Self(Small(small)) => limbs_neg_limb_get_bits(small, start, end),
202 Self(Large(limbs)) => limbs_vec_neg_get_bits(limbs, start, end),
203 })
204 }
205
206 fn neg_assign_bits(&mut self, start: u64, end: u64, bits: &Self) {
207 if start == end {
208 return;
209 }
210 let bits_width = end - start;
211 if bits_width <= Limb::WIDTH
212 && let (&mut Self(Small(ref mut small_self)), &Self(Small(small_bits))) =
213 (&mut *self, bits)
214 {
215 let small_bits = (!small_bits).mod_power_of_2(bits_width);
216 if small_bits == 0 || LeadingZeros::leading_zeros(small_bits) >= start {
217 let mut new_small_self = *small_self - 1;
218 new_small_self.assign_bits(start, end, &small_bits);
219 let (sum, overflow) = new_small_self.overflowing_add(1);
220 if !overflow {
221 *small_self = sum;
222 return;
223 }
224 }
225 }
226 let limbs = self.promote_in_place();
227 match bits {
228 Self(Small(small_bits)) => limbs_neg_assign_bits(limbs, start, end, &[*small_bits]),
229 Self(Large(bits_limbs)) => limbs_neg_assign_bits(limbs, start, end, bits_limbs),
230 }
231 self.trim();
232 }
233}
234
235impl BitBlockAccess for Integer {
236 type Bits = Natural;
237
238 /// Extracts a block of adjacent two's complement bits from an [`Integer`], taking the
239 /// [`Integer`] by reference.
240 ///
241 /// The first index is `start` and last index is `end - 1`.
242 ///
243 /// Let $n$ be `self`, and let $p$ and $q$ be `start` and `end`, respectively.
244 ///
245 /// If $n \geq 0$, let
246 /// $$
247 /// n = \sum_{i=0}^\infty 2^{b_i};
248 /// $$
249 /// but if $n < 0$, let
250 /// $$
251 /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
252 /// $$
253 /// where for all $i$, $b_i\in \\{0, 1\\}$. Then
254 /// $$
255 /// f(n, p, q) = \sum_{i=p}^{q-1} 2^{b_{i-p}}.
256 /// $$
257 ///
258 /// # Worst-case complexity
259 /// $T(n) = O(n)$
260 ///
261 /// $M(n) = O(n)$
262 ///
263 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(), end)`.
264 ///
265 /// # Panics
266 /// Panics if `start > end`.
267 ///
268 /// # Examples
269 /// ```
270 /// use core::str::FromStr;
271 /// use malachite_base::num::basic::traits::Zero;
272 /// use malachite_base::num::logic::traits::BitBlockAccess;
273 /// use malachite_nz::integer::Integer;
274 /// use malachite_nz::natural::Natural;
275 ///
276 /// assert_eq!(
277 /// (-Natural::from(0xabcdef0112345678u64)).get_bits(16, 48),
278 /// Natural::from(0x10feedcbu32)
279 /// );
280 /// assert_eq!(
281 /// Integer::from(0xabcdef0112345678u64).get_bits(4, 16),
282 /// Natural::from(0x567u32)
283 /// );
284 /// assert_eq!(
285 /// (-Natural::from(0xabcdef0112345678u64)).get_bits(0, 100),
286 /// Natural::from_str("1267650600215849587758112418184").unwrap()
287 /// );
288 /// assert_eq!(
289 /// Integer::from(0xabcdef0112345678u64).get_bits(10, 10),
290 /// Natural::ZERO
291 /// );
292 /// ```
293 fn get_bits(&self, start: u64, end: u64) -> Natural {
294 if self.sign {
295 self.abs.get_bits(start, end)
296 } else {
297 self.abs.neg_get_bits(start, end)
298 }
299 }
300
301 /// Extracts a block of adjacent two's complement bits from an [`Integer`], taking the
302 /// [`Integer`] by value.
303 ///
304 /// The first index is `start` and last index is `end - 1`.
305 ///
306 /// Let $n$ be `self`, and let $p$ and $q$ be `start` and `end`, respectively.
307 ///
308 /// If $n \geq 0$, let
309 /// $$
310 /// n = \sum_{i=0}^\infty 2^{b_i};
311 /// $$
312 /// but if $n < 0$, let
313 /// $$
314 /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
315 /// $$
316 /// where for all $i$, $b_i\in \\{0, 1\\}$. Then
317 /// $$
318 /// f(n, p, q) = \sum_{i=p}^{q-1} 2^{b_{i-p}}.
319 /// $$
320 ///
321 /// # Worst-case complexity
322 /// $T(n) = O(n)$
323 ///
324 /// $M(n) = O(n)$
325 ///
326 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(), end)`.
327 ///
328 /// # Panics
329 /// Panics if `start > end`.
330 ///
331 /// # Examples
332 /// ```
333 /// use core::str::FromStr;
334 /// use malachite_base::num::basic::traits::Zero;
335 /// use malachite_base::num::logic::traits::BitBlockAccess;
336 /// use malachite_nz::integer::Integer;
337 /// use malachite_nz::natural::Natural;
338 ///
339 /// assert_eq!(
340 /// (-Natural::from(0xabcdef0112345678u64)).get_bits_owned(16, 48),
341 /// Natural::from(0x10feedcbu32)
342 /// );
343 /// assert_eq!(
344 /// Integer::from(0xabcdef0112345678u64).get_bits_owned(4, 16),
345 /// Natural::from(0x567u32)
346 /// );
347 /// assert_eq!(
348 /// (-Natural::from(0xabcdef0112345678u64)).get_bits_owned(0, 100),
349 /// Natural::from_str("1267650600215849587758112418184").unwrap()
350 /// );
351 /// assert_eq!(
352 /// Integer::from(0xabcdef0112345678u64).get_bits_owned(10, 10),
353 /// Natural::ZERO
354 /// );
355 /// ```
356 fn get_bits_owned(self, start: u64, end: u64) -> Natural {
357 if self.sign {
358 self.abs.get_bits_owned(start, end)
359 } else {
360 self.abs.neg_get_bits_owned(start, end)
361 }
362 }
363
364 /// Replaces a block of adjacent two's complement bits in an [`Integer`] with other bits.
365 ///
366 /// The least-significant `end - start` bits of `bits` are assigned to bits `start` through `end
367 /// - 1`, inclusive, of `self`.
368 ///
369 /// Let $n$ be `self` and let $m$ be `bits`, and let $p$ and $q$ be `start` and `end`,
370 /// respectively.
371 ///
372 /// Let
373 /// $$
374 /// m = \sum_{i=0}^k 2^{d_i},
375 /// $$
376 /// where for all $i$, $d_i\in \\{0, 1\\}$.
377 ///
378 /// If $n \geq 0$, let
379 /// $$
380 /// n = \sum_{i=0}^\infty 2^{b_i};
381 /// $$
382 /// but if $n < 0$, let
383 /// $$
384 /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
385 /// $$
386 /// where for all $i$, $b_i\in \\{0, 1\\}$. Then
387 /// $$
388 /// n \gets \sum_{i=0}^\infty 2^{c_i},
389 /// $$
390 /// where
391 /// $$
392 /// \\{c_0, c_1, c_2, \ldots \\} =
393 /// \\{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 \\}.
394 /// $$
395 ///
396 /// # Worst-case complexity
397 /// $T(n) = O(n)$
398 ///
399 /// $M(m) = O(m)$
400 ///
401 /// where $T$ is time, $M$ is additional memory, $n$ is `max(self.significant_bits(), end)`, and
402 /// $m$ is `self.significant_bits()`.
403 ///
404 /// # Panics
405 /// Panics if `start > end`.
406 ///
407 /// # Examples
408 /// ```
409 /// use malachite_base::num::logic::traits::BitBlockAccess;
410 /// use malachite_nz::integer::Integer;
411 /// use malachite_nz::natural::Natural;
412 ///
413 /// let mut n = Integer::from(123);
414 /// n.assign_bits(5, 7, &Natural::from(456u32));
415 /// assert_eq!(n.to_string(), "27");
416 ///
417 /// let mut n = Integer::from(-123);
418 /// n.assign_bits(64, 128, &Natural::from(456u32));
419 /// assert_eq!(n.to_string(), "-340282366920938455033212565746503123067");
420 ///
421 /// let mut n = Integer::from(-123);
422 /// n.assign_bits(80, 100, &Natural::from(456u32));
423 /// assert_eq!(n.to_string(), "-1267098121128665515963862483067");
424 /// ```
425 fn assign_bits(&mut self, start: u64, end: u64, bits: &Natural) {
426 if self.sign {
427 self.abs.assign_bits(start, end, bits);
428 } else {
429 self.abs.neg_assign_bits(start, end, bits);
430 }
431 }
432}