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}