Skip to main content

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}