malachite_base/num/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::num::arithmetic::traits::{ModPowerOf2, UnsignedAbs};
10use crate::num::basic::signeds::PrimitiveSigned;
11use crate::num::basic::unsigneds::PrimitiveUnsigned;
12use crate::num::conversion::traits::WrappingFrom;
13use crate::num::logic::traits::{BitBlockAccess, LeadingZeros};
14use core::cmp::min;
15
16const ERROR_MESSAGE: &str = "Result exceeds width of output type";
17
18fn get_bits_unsigned<T: PrimitiveUnsigned>(x: &T, start: u64, end: u64) -> T {
19    assert!(start <= end);
20    if start >= T::WIDTH {
21        T::ZERO
22    } else {
23        (*x >> start).mod_power_of_2(end - start)
24    }
25}
26
27fn assign_bits_unsigned<T: PrimitiveUnsigned>(x: &mut T, start: u64, end: u64, bits: &T) {
28    assert!(start <= end);
29    let width = T::WIDTH;
30    let bits_width = end - start;
31    let bits = bits.mod_power_of_2(bits_width);
32    if bits != T::ZERO && LeadingZeros::leading_zeros(bits) < start {
33        panic!("{}", ERROR_MESSAGE);
34    } else if start < width {
35        *x &= !(T::MAX.mod_power_of_2(min(bits_width, width - start)) << start);
36        *x |= bits << start;
37    }
38}
39
40macro_rules! impl_bit_block_access_unsigned {
41    ($t:ident) => {
42        impl BitBlockAccess for $t {
43            type Bits = $t;
44
45            /// Extracts a block of adjacent bits from a number.
46            ///
47            /// The first index is `start` and last index is `end - 1`.
48            ///
49            /// The block of bits has the same type as the input. If `end` is greater than the
50            /// type's width, the high bits of the result are all 0.
51            ///
52            /// Let
53            /// $$
54            /// n = \sum_{i=0}^\infty 2^{b_i},
55            /// $$
56            /// where for all $i$, $b_i\in \\{0, 1\\}$; so finitely many of the bits are 1, and the
57            /// rest are 0. Then
58            /// $$
59            /// f(n, p, q) = \sum_{i=p}^{q-1} 2^{b_{i-p}}.
60            /// $$
61            ///
62            /// # Worst-case complexity
63            /// Constant time and additional memory.
64            ///
65            /// # Panics
66            /// Panics if `start < end`.
67            ///
68            /// # Examples
69            /// See [here](super::bit_block_access#get_bits).
70            #[inline]
71            fn get_bits(&self, start: u64, end: u64) -> Self {
72                get_bits_unsigned(self, start, end)
73            }
74
75            /// Replaces a block of adjacent bits in a number with other bits.
76            ///
77            /// The least-significant `end - start` bits of `bits` are assigned to bits `start`
78            /// through `end - 1`, inclusive, of `self`.
79            ///
80            /// The block of bits has the same type as the input. If `bits` has fewer bits than `end
81            /// - start`, the high bits are interpreted as 0. If `end` is greater than the type's
82            /// width, the high bits of `bits` must be 0.
83            ///
84            /// Let
85            /// $$
86            /// n = \sum_{i=0}^{W-1} 2^{b_i},
87            /// $$
88            /// where for all $i$, $b_i\in \\{0, 1\\}$ and $W$ is `$t::WIDTH`. Let
89            /// $$
90            /// m = \sum_{i=0}^k 2^{d_i},
91            /// $$
92            /// where for all $i$, $d_i\in \\{0, 1\\}$. Also, let $p, q \in \mathbb{N}$, where $d_i
93            /// = 0$ for all $i \geq W + p$.
94            ///
95            /// Then
96            /// $$
97            /// n \gets \sum_{i=0}^{W-1} 2^{c_i},
98            /// $$
99            /// where
100            /// $$
101            /// \\{c_0, c_1, c_2, \ldots, c_ {W-1}\\} =
102            /// \\{b_0, b_1, b_2, \ldots, b_{p-1}, d_0, d_1, \ldots, d_{p-q-1}, b_q, \ldots,
103            /// b_ {W-1}\\}.
104            /// $$
105            ///
106            /// # Worst-case complexity
107            /// Constant time and additional memory.
108            ///
109            /// # Panics
110            /// Let `W` be the type's width. Panics if `start < end`, or if `end > W` and bits `W -
111            /// start` through `end - start` of `bits` are nonzero.
112            ///
113            /// # Examples
114            /// See [here](super::bit_block_access#assign_bits).
115            #[inline]
116            fn assign_bits(&mut self, start: u64, end: u64, bits: &Self::Bits) {
117                assign_bits_unsigned(self, start, end, bits)
118            }
119        }
120    };
121}
122apply_to_unsigneds!(impl_bit_block_access_unsigned);
123
124fn get_bits_signed<T: ModPowerOf2<Output = U> + PrimitiveSigned, U>(
125    x: &T,
126    start: u64,
127    end: u64,
128) -> U {
129    assert!(start <= end);
130    (if start >= T::WIDTH {
131        -T::from(*x < T::ZERO)
132    } else {
133        *x >> start
134    })
135    .mod_power_of_2(end - start)
136}
137
138fn assign_bits_signed<
139    T: PrimitiveSigned + UnsignedAbs<Output = U> + WrappingFrom<U>,
140    U: PrimitiveUnsigned,
141>(
142    x: &mut T,
143    start: u64,
144    end: u64,
145    bits: &U,
146) {
147    assert!(start <= end);
148    if *x >= T::ZERO {
149        let mut abs_x = x.unsigned_abs();
150        abs_x.assign_bits(start, end, bits);
151        assert!(!abs_x.get_highest_bit(), "{ERROR_MESSAGE}");
152        *x = T::wrapping_from(abs_x);
153    } else {
154        let width = T::WIDTH - 1;
155        let bits_width = end - start;
156        let bits = bits.mod_power_of_2(bits_width);
157        let max = U::MAX;
158        if bits_width > width + 1 {
159            panic!("{}", ERROR_MESSAGE);
160        } else if start >= width {
161            assert!(bits == max.mod_power_of_2(bits_width), "{ERROR_MESSAGE}");
162        } else {
163            let lower_width = width - start;
164            if end > width && bits >> lower_width != max.mod_power_of_2(end - width) {
165                panic!("{}", ERROR_MESSAGE);
166            } else {
167                *x &=
168                    T::wrapping_from(!(max.mod_power_of_2(min(bits_width, lower_width)) << start));
169                *x |= T::wrapping_from(bits << start);
170            }
171        }
172    }
173}
174
175macro_rules! impl_bit_block_access_signed {
176    ($u:ident, $s:ident) => {
177        impl BitBlockAccess for $s {
178            type Bits = $u;
179
180            /// Extracts a block of adjacent bits from a number.
181            ///
182            /// The first index is `start` and last index is `end - 1`.
183            ///
184            /// The type of the block of bits is the unsigned version of the input type. If `end` is
185            /// greater than the type's width, the high bits of the result are all 0, or all 1,
186            /// depending on the input value's sign; and if the input is negative and `end - start`
187            /// is greater than the type's width, the function panics.
188            ///
189            /// If $n \geq 0$, let
190            /// $$
191            /// n = \sum_{i=0}^\infty 2^{b_i},
192            /// $$
193            /// where for all $i$, $b_i\in \\{0, 1\\}$; so finitely many of the bits are 1, and the
194            /// rest are 0. Then
195            /// $$
196            /// f(n, p, q) = \sum_{i=p}^{q-1} 2^{b_{i-p}}.
197            /// $$
198            ///
199            /// If $n < 0$, let
200            /// $$
201            /// 2^W + n = \sum_{i=0}^{W-1} 2^{b_i},
202            /// $$
203            /// where
204            /// - $W$ is the type's width
205            /// - for all $i$, $b_i\in \\{0, 1\\}$, and $b_i = 1$ for $i \geq W$.
206            ///
207            /// Then
208            /// $$
209            /// f(n, p, q) = \sum_{i=p}^{q-1} 2^{b_{i-p}}.
210            /// $$
211            ///
212            /// # Worst-case complexity
213            /// Constant time and additional memory.
214            ///
215            /// # Panics
216            /// Let `W` be the type's width. Panics if `start < end` or (`self < 0` and `end - start
217            /// > W`).
218            ///
219            /// # Examples
220            /// See [here](super::bit_block_access#get_bits).
221            #[inline]
222            fn get_bits(&self, start: u64, end: u64) -> Self::Bits {
223                get_bits_signed(self, start, end)
224            }
225
226            /// Replaces a block of adjacent bits in a number with other bits.
227            ///
228            /// The least-significant `end - start` bits of `bits` are assigned to bits `start`
229            /// through `end - 1`, inclusive, of `self`.
230            ///
231            /// The type of the block of bits is the unsigned version of the input type. If `bits`
232            /// has fewer bits than `end - start`, the high bits are interpreted as 0 or 1,
233            /// depending on the sign of `self`. If `end` is greater than the type's width, the high
234            /// bits of `bits` must be 0 or 1, depending on the sign of `self`.
235            ///
236            /// The sign of `self` remains unchanged, since only a finite number of bits are changed
237            /// and the sign is determined by the implied infinite prefix of bits.
238            ///
239            /// If $n \geq 0$ and $j \neq W - 1$, let
240            /// $$
241            /// n = \sum_{i=0}^{W-1} 2^{b_i},
242            /// $$
243            /// where for all $i$, $b_i\in \\{0, 1\\}$ and $W$ is `$t::WIDTH`. Let
244            /// $$
245            /// m = \sum_{i=0}^k 2^{d_i},
246            /// $$
247            /// where for all $i$, $d_i\in \\{0, 1\\}$. Also, let $p, q \in \mathbb{N}$, where $d_i
248            /// = 0$ for all $i \geq W + p - 1$. Then
249            /// $$
250            /// n \gets \sum_{i=0}^{W-1} 2^{c_i},
251            /// $$
252            /// where
253            /// $$
254            /// \\{c_0, c_1, c_2, \ldots, c_ {W-1}\\} =
255            /// \\{b_0, b_1, b_2, \ldots, b_{p-1}, d_0, d_1, \ldots, d_{p-q-1}, b_q, \ldots,
256            /// b_ {W-1}\\}.
257            /// $$
258            ///
259            /// If $n < 0$ or $j = W - 1$, let
260            /// $$
261            /// 2^W + n = \sum_{i=0}^{W-1} 2^{b_i},
262            /// $$
263            /// where for all $i$, $b_i\in \\{0, 1\\}$ and $W$ is `$t::WIDTH`. Let
264            /// $$
265            /// m = \sum_{i=0}^k 2^{d_i},
266            /// $$
267            /// where for all $i$, $d_i\in \\{0, 1\\}$. Also, let $p, q \in \mathbb{N}$, where $d_i
268            /// = 1$ for all $i \geq W + p - 1$. Then
269            /// $$
270            /// f(n, p, q, m) = \left ( \sum_{i=0}^{W-1} 2^{c_i} \right ) - 2^W,
271            /// $$
272            /// where
273            /// $$
274            /// \\{c_0, c_1, c_2, \ldots, c_ {W-1}\\} =
275            /// \\{b_0, b_1, b_2, \ldots, b_{p-1}, d_0, d_1, \ldots, d_{p-q-1}, b_q, \ldots,
276            /// b_ {W-1}\\}.
277            /// $$
278            ///
279            /// # Worst-case complexity
280            /// Constant time and additional memory.
281            ///
282            /// # Panics
283            /// Let `W` be the type's width Panics if `start < end`, or if `end >= W` and bits `W -
284            /// start` through `end - start` of `bits` are not equal to the original sign bit of
285            /// `self`.
286            ///
287            /// # Examples
288            /// See [here](super::bit_block_access#assign_bits).
289            #[inline]
290            fn assign_bits(&mut self, start: u64, end: u64, bits: &Self::Bits) {
291                assign_bits_signed(self, start, end, bits)
292            }
293        }
294    };
295}
296apply_to_unsigned_signed_pairs!(impl_bit_block_access_signed);