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);