a/math/numbers/bits.rs
1//! Bitwise operations on [`Number`]s: `&`, `|`, `^`, `&=`, `|=` and `^=`, with either operand
2//! owned or borrowed, `!`, and the bits of a number: [`Number::bits`], [`Number::count_ones`],
3//! [`Number::trailing_zeros`], [`Number::bit`] and [`Number::set_bit`].
4//!
5//! The operators work as if both operands were in two's complement with infinitely many bits, as
6//! those of `i32` do on 32 and GMP's `mpz_and`, `mpz_ior`, `mpz_xor` and `mpz_com` on any number:
7//! a negative number has infinitely many ones above its magnitude's bits, `-x` being `!x + 1`. The
8//! result is stored back as a sign and a magnitude. With `X` and `Y` the magnitudes, a negative
9//! operand is `!(X - 1)` and a negative result `!(R - 1)`, so every combination of signs comes down
10//! to one operation `g` on the bytes of `X` or `X - 1` and `Y` or `Y - 1`, plus one when the result
11//! is negative:
12//!
13//! | | `x & y` | `x \| y` | `x ^ y` |
14//! | --- | --- | --- | --- |
15//! | `+ +` | `X & Y` | `X \| Y` | `X ^ Y` |
16//! | `+ -` | `X & !(Y - 1)` | `-((Y - 1) & !X) - 1` | `-(X ^ (Y - 1)) - 1` |
17//! | `- +` | `!(X - 1) & Y` | `-((X - 1) & !Y) - 1` | `-((X - 1) ^ Y) - 1` |
18//! | `- -` | `-((X - 1) \| (Y - 1)) - 1` | `-((X - 1) & (Y - 1)) - 1` | `(X - 1) ^ (Y - 1)` |
19//!
20//! `!x` is `-x - 1`: `-(X + 1)` for `x >= 0`, and `X - 1` for `x < 0`.
21//!
22//! The ones taken from the magnitudes and the one added to the result are borrows and a carry
23//! that run through the low bytes only: `X - 1` differs from `X` below its lowest nonzero byte
24//! and at it, and the carry of `R + 1` runs through the bytes of `R` that are `0xFF`. So the
25//! result is computed limb by limb (eight bytes, the least significant first) with the borrows
26//! and the carry in flags, from the low end until all three are spent, which for random operands
27//! is the first limb: the head. Above it, each byte of the result is `g` of the bytes of the
28//! magnitudes at its position, with no carry from one byte to the next, so the rest is a loop
29//! over the bytes in the order of memory, the same for both byte orders: NEON on aarch64, sixteen
30//! bytes a step (`and`, `orr`, `eor` or `bic`), and words of eight bytes elsewhere. Above the
31//! shorter operand, the result is the longer one's bytes or zero, by the operation.
32//!
33//! The paths, by the operands:
34//!
35//! - Both vectors of at most 16 bytes: in registers, as `u128`s in two's complement.
36//! - Neither negative, in the same byte order: the operation, known at compile time, runs over
37//! the shorter magnitude's bytes with the kernel, with no borrow or carry, straight into the
38//! vector the result goes to; its length is the longer magnitude's for `|` and `^` of different
39//! lengths, and is otherwise read from the top down, one read for random operands: of the
40//! result, in place little-endian, and of the operands otherwise.
41//! - Both of at most 64 bytes otherwise: in registers, as up to eight limbs each, as the
42//! addition's medium path reads them, with no branch on the signs or the length.
43//! - Longer ones, in an operand's vector with room: the head of one limb, the length from the top
44//! of the operands (one read), one kernel call and a copy of the longer operand's top bytes.
45//! - Otherwise (a new vector, a longer head, or a big-endian result of another length than the
46//! vector it is built in), everything about the result but its bytes is planned first, as for
47//! the other operators: the head, by a pass over its limbs that only reads them, and the exact
48//! length. Only then is a vector chosen, and the result written in it, each byte once; in place,
49//! the bytes the longer operand gives are left where they are, and a big-endian result that
50//! moves is written in the order that reads every byte of the operand before it is written over.
51
52// The kernels of the loops over the bytes, under the name `kernels`: NEON on the 64-bit
53// little-endian aarch64 targets whose operating system allows unaligned accesses (those of the
54// addition's assembly), where NEON is enabled, as it is by default; the portable ones elsewhere and
55// under Miri, which runs no SIMD of this kind.
56#[cfg(all(
57 target_arch = "aarch64",
58 target_endian = "little",
59 target_pointer_width = "64",
60 target_feature = "neon",
61 any(
62 target_vendor = "apple",
63 target_os = "linux",
64 target_os = "android",
65 target_os = "windows",
66 target_os = "freebsd",
67 target_os = "netbsd",
68 target_os = "openbsd",
69 target_os = "fuchsia"
70 ),
71 not(miri)
72))]
73#[path = "bits/aarch64.rs"]
74mod kernels;
75#[cfg(not(all(
76 target_arch = "aarch64",
77 target_endian = "little",
78 target_pointer_width = "64",
79 target_feature = "neon",
80 any(
81 target_vendor = "apple",
82 target_os = "linux",
83 target_os = "android",
84 target_os = "windows",
85 target_os = "freebsd",
86 target_os = "netbsd",
87 target_os = "openbsd",
88 target_os = "fuchsia"
89 ),
90 not(miri)
91)))]
92#[path = "bits/portable.rs"]
93mod kernels;
94
95use super::add::{
96 SMALL, long, medium, read, read_limbs, read_small, significant_len, small, top_of, write,
97 write_small,
98};
99use super::{ByteOrder, Number};
100use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
101use core::{mem, ptr};
102
103// The operations on the bytes of two magnitudes `x` and `y` that the operators come down to.
104
105/// `x & y`.
106const AND: u8 = 0;
107/// `x | y`.
108const OR: u8 = 1;
109/// `x ^ y`.
110const XOR: u8 = 2;
111/// `x & !y`.
112const AND_NOT: u8 = 3;
113/// `!x & y`.
114const NOT_AND: u8 = 4;
115
116/// The operation `g` on the words `x` and `y`.
117#[inline(always)]
118fn apply(g: u8, x: u64, y: u64) -> u64 {
119 match g {
120 AND => x & y,
121 OR => x | y,
122 XOR => x ^ y,
123 AND_NOT => x & !y,
124 _ => !x & y,
125 }
126}
127
128/// A bitwise operator on two numbers.
129#[derive(Clone, Copy)]
130#[repr(u8)]
131enum Op {
132 And,
133 Or,
134 Xor,
135}
136
137/// The operation on the magnitudes and the sign of the result of `op` for operands with the signs
138/// `nx` and `ny`, as in the table of the module: the result is `g(X', Y')`, plus one when it is
139/// negative, with `X' = X - 1` for a negative `x` and `X` otherwise, and `Y'` likewise. Read from
140/// a table, with no branch.
141#[inline(always)]
142fn select(op: Op, nx: bool, ny: bool) -> (u8, bool) {
143 /// `g` in the low bits and the sign of the result in the top one, by the operator and the
144 /// signs `nx ny` of the operands: `+ +`, `+ -`, `- +`, `- -`.
145 const TABLE: [[u8; 4]; 3] = [
146 [AND, AND_NOT, NOT_AND, OR | 0x80],
147 [OR, NOT_AND | 0x80, AND_NOT | 0x80, AND | 0x80],
148 [XOR, XOR | 0x80, XOR | 0x80, XOR],
149 ];
150 let t = TABLE[op as usize][usize::from(nx) * 2 + usize::from(ny)];
151 (t & 0x7F, t & 0x80 != 0)
152}
153
154// The operators
155
156/// Implements a bitwise operator: `$Op` with its method `$op` for each form of the operands, and
157/// `$Assign` with `$assign`. `$sym` is the operator; the examples compute `12 $sym -10`, which is
158/// `$value` (`$magnitude` and `$negative`), `0x0F_00 $sym 0x00_F0` (`$wide`, as stored
159/// big-endian) and `0xFF $sym 0x01_00` (`$by_b`, stored as `$in_b`, in the vector of the right
160/// operand when `$built_in_b`).
161macro_rules! bitwise {
162 (
163 $Op:ident, $op:ident, $Assign:ident, $assign:ident, $kind:expr, $OP:expr, $sym:literal,
164 $what:literal, $value:literal, $magnitude:literal, $negative:literal, $wide:literal,
165 $by_b:literal, $in_b:literal, $built_in_b:literal
166 ) => {
167 impl $Op<&Number> for &Number {
168 type Output = Number;
169
170 #[doc = concat!("Returns `self ", $sym, " rhs`, the bitwise ", $what, " of the numbers in")]
171 /// infinite two's complement, in the byte order of `self`, in the shortest form.
172 ///
173 /// The result is built in one new vector of exactly its length (one byte for zero);
174 /// both operands are left as they were. The operands may have any signs, byte orders
175 /// and lengths, and need not be in the shortest form.
176 ///
177 /// # Examples
178 ///
179 /// ```
180 /// use a::math::numbers::{ByteOrder, Number};
181 ///
182 /// let a = Number::new_from_i32(12, ByteOrder::BigEndian);
183 /// let b = Number::new_from_i32(-10, ByteOrder::LittleEndian);
184 #[doc = concat!("let c = &a ", $sym, " &b;")]
185 #[doc = concat!("// As for `i32`: `12 ", $sym, " -10` is ", $value, ".")]
186 #[doc = concat!("assert_eq!(c.value, [", $magnitude, "]);")]
187 #[doc = concat!("assert_eq!(c.is_negative(), ", $negative, ");")]
188 /// assert!(c.byte_order() == ByteOrder::BigEndian);
189 /// ```
190 fn $op(self, rhs: &Number) -> Number {
191 if small(self, rhs) {
192 // SAFETY: both vectors hold at most 16 bytes.
193 let s = unsafe { small_result(self, rhs, $kind) };
194 return small_number(self.byte_order, s);
195 }
196 if let Some(n) = plus_new::<{ $OP }>(self, rhs) {
197 return n;
198 }
199 if medium(self, rhs) {
200 // SAFETY: both vectors hold at most 64 bytes.
201 let m = unsafe { medium_result::<{ $OP }>(self, rhs) };
202 return medium_number(self.byte_order, &m);
203 }
204 ref_ref(self, rhs, $kind)
205 }
206 }
207
208 impl $Op<&Number> for Number {
209 type Output = Number;
210
211 #[doc = concat!("Returns `self ", $sym, " rhs`, in the byte order of `self`, in the shortest")]
212 #[doc = concat!("form, as `self ", $sym, "= rhs` does.")]
213 ///
214 /// The result is built in the vector of `self` when its capacity has room for it,
215 /// which allocates nothing, and otherwise in one new vector of exactly its length.
216 /// `rhs` is left as it was.
217 ///
218 /// # Examples
219 ///
220 /// ```
221 /// use a::math::numbers::{ByteOrder, Number};
222 ///
223 /// let mut value = Vec::with_capacity(4);
224 /// value.extend([0x0F, 0x00]);
225 /// let a = Number::new(value, ByteOrder::BigEndian);
226 /// let pointer = a.value.as_ptr();
227 ///
228 #[doc = concat!("let c = a ", $sym, " &Number::new_from_u8(0xF0, ByteOrder::LittleEndian);")]
229 #[doc = concat!("assert_eq!(c.value, [", $wide, "]);")]
230 /// assert_eq!(c.value.as_ptr(), pointer);
231 /// ```
232 fn $op(mut self, rhs: &Number) -> Number {
233 $Assign::$assign(&mut self, rhs);
234 self
235 }
236 }
237
238 impl $Op<Number> for &Number {
239 type Output = Number;
240
241 #[doc = concat!("Returns `self ", $sym, " rhs`, in the byte order of `self`, in the shortest")]
242 /// form.
243 ///
244 /// The result is built in the vector of `rhs` when its capacity has room for it, also
245 /// when `rhs` is in the other byte order, and otherwise in one new vector of exactly
246 /// its length. `self` is left as it was.
247 ///
248 /// # Examples
249 ///
250 /// ```
251 /// use a::math::numbers::{ByteOrder, Number};
252 ///
253 /// let a = Number::new_from_u16(0x0F00, ByteOrder::BigEndian);
254 /// let mut value = Vec::with_capacity(4);
255 /// value.extend([0xF0]);
256 /// let b = Number::new(value, ByteOrder::LittleEndian);
257 /// let pointer = b.value.as_ptr();
258 ///
259 #[doc = concat!("let c = &a ", $sym, " b;")]
260 #[doc = concat!("assert_eq!(c.value, [", $wide, "]);")]
261 /// assert_eq!(c.value.as_ptr(), pointer);
262 /// assert!(c.byte_order() == ByteOrder::BigEndian);
263 /// ```
264 fn $op(self, mut rhs: Number) -> Number {
265 if small(self, &rhs) {
266 // SAFETY: both vectors hold at most 16 bytes.
267 let s = unsafe { small_result(self, &rhs, $kind) };
268 let order = self.byte_order;
269 put_small(&mut rhs.value, order, s);
270 return Number {
271 value: rhs.value,
272 negative: s.negative,
273 byte_order: order,
274 };
275 }
276 // The operations are symmetric: `rhs op self` over `rhs`.
277 if plus_over::<{ $OP }>(&mut rhs, self) {
278 return rhs;
279 }
280 if medium(self, &rhs) {
281 // SAFETY: both vectors hold at most 64 bytes.
282 let m = unsafe { medium_result::<{ $OP }>(self, &rhs) };
283 let order = self.byte_order;
284 put_medium(&mut rhs.value, order, &m);
285 return Number {
286 value: rhs.value,
287 negative: m.negative,
288 byte_order: order,
289 };
290 }
291 // `rhs` is dropped on return, with the vector it holds then, if any.
292 ref_value(self, &mut rhs, $kind)
293 }
294 }
295
296 impl $Op<Number> for Number {
297 type Output = Number;
298
299 #[doc = concat!("Returns `self ", $sym, " rhs`, in the byte order of `self`, in the shortest")]
300 #[doc = concat!("form, as `self ", $sym, "= rhs` does.")]
301 ///
302 /// The result is built in the vector of `self` when its capacity has room for it, or
303 /// else in the vector of `rhs` when that has room, also when `rhs` is in the other
304 /// byte order, either of which allocates nothing; otherwise it gets one new vector of
305 /// exactly its length.
306 ///
307 /// # Examples
308 ///
309 /// ```
310 /// use a::math::numbers::{ByteOrder, Number};
311 ///
312 /// let a = Number::new_from_i32(12, ByteOrder::LittleEndian);
313 /// let b = Number::new_from_i32(-10, ByteOrder::BigEndian);
314 #[doc = concat!("let c = a ", $sym, " b;")]
315 #[doc = concat!("assert_eq!(c.value, [", $magnitude, "]);")]
316 #[doc = concat!("assert_eq!(c.is_negative(), ", $negative, ");")]
317 /// ```
318 fn $op(mut self, rhs: Number) -> Number {
319 $Assign::$assign(&mut self, rhs);
320 self
321 }
322 }
323
324 impl $Assign<&Number> for Number {
325 #[doc = concat!("Sets `self` to `self ", $sym, " rhs`, keeping its byte order, in the shortest form.")]
326 ///
327 /// The result is built in the vector of `self` when its capacity has room for it,
328 /// which allocates nothing, and otherwise in one new vector of exactly its length,
329 /// which replaces it. `rhs` is left as it was.
330 ///
331 /// # Examples
332 ///
333 /// ```
334 /// use a::math::numbers::{ByteOrder, Number};
335 ///
336 /// let mut n = Number::new_from_i32(12, ByteOrder::LittleEndian);
337 #[doc = concat!("n ", $sym, "= &Number::new_from_i32(-10, ByteOrder::BigEndian);")]
338 #[doc = concat!("assert_eq!(n.value, [", $magnitude, "]);")]
339 #[doc = concat!("assert_eq!(n.is_negative(), ", $negative, ");")]
340 /// ```
341 #[inline]
342 fn $assign(&mut self, rhs: &Number) {
343 if small(self, rhs) {
344 // SAFETY: both vectors hold at most 16 bytes.
345 let s = unsafe { small_result(self, rhs, $kind) };
346 put_small(&mut self.value, self.byte_order, s);
347 self.negative = s.negative;
348 return;
349 }
350 if plus_over::<{ $OP }>(self, rhs) {
351 return;
352 }
353 if medium(self, rhs) {
354 // SAFETY: both vectors hold at most 64 bytes.
355 let m = unsafe { medium_result::<{ $OP }>(self, rhs) };
356 put_medium(&mut self.value, self.byte_order, &m);
357 self.negative = m.negative;
358 return;
359 }
360 assign_ref(self, rhs, $kind);
361 }
362 }
363
364 impl $Assign<Number> for Number {
365 #[doc = concat!("Sets `self` to `self ", $sym, " rhs`, keeping its byte order, in the shortest form.")]
366 ///
367 /// The result is built in the vector of `self` when its capacity has room for it, or
368 /// else in the vector of `rhs` when that has room, also when `rhs` is in the other
369 /// byte order, either of which allocates nothing; otherwise it gets one new vector of
370 /// exactly its length.
371 ///
372 /// # Examples
373 ///
374 /// ```
375 /// use a::math::numbers::{ByteOrder, Number};
376 ///
377 /// // `n` has room for one byte only; the vector of the right operand has more.
378 /// let mut value = Vec::with_capacity(1);
379 /// value.push(0xFF);
380 /// let mut n = Number::new(value, ByteOrder::BigEndian);
381 /// let mut value = Vec::with_capacity(4);
382 /// value.extend([0x00, 0x01]);
383 /// let b = Number::new(value, ByteOrder::LittleEndian);
384 /// let pointer = b.value.as_ptr();
385 #[doc = concat!("n ", $sym, "= b;")]
386 #[doc = concat!("// `0xFF ", $sym, " 0x01_00` is ", $by_b, ".")]
387 #[doc = concat!("assert_eq!(n.value, [", $in_b, "]);")]
388 #[doc = concat!("assert_eq!(n.value.as_ptr() == pointer, ", $built_in_b, ");")]
389 /// ```
390 #[inline]
391 fn $assign(&mut self, mut rhs: Number) {
392 if small(self, &rhs) {
393 // SAFETY: both vectors hold at most 16 bytes.
394 let s = unsafe { small_result(self, &rhs, $kind) };
395 if self.value.capacity() < s.len && rhs.value.capacity() >= s.len {
396 // The vector of `self` goes to `rhs`, and is dropped with it.
397 mem::swap(&mut self.value, &mut rhs.value);
398 }
399 put_small(&mut self.value, self.byte_order, s);
400 self.negative = s.negative;
401 return;
402 }
403 if plus_over::<{ $OP }>(self, &rhs) {
404 return;
405 }
406 if medium(self, &rhs) {
407 // SAFETY: both vectors hold at most 64 bytes.
408 let m = unsafe { medium_result::<{ $OP }>(self, &rhs) };
409 if self.value.capacity() < m.len && rhs.value.capacity() >= m.len {
410 // The vector of `self` goes to `rhs`, and is dropped with it.
411 mem::swap(&mut self.value, &mut rhs.value);
412 }
413 put_medium(&mut self.value, self.byte_order, &m);
414 self.negative = m.negative;
415 return;
416 }
417 // `rhs` is dropped on return, with the vector it holds then.
418 assign_value(self, &mut rhs, $kind);
419 }
420 }
421 };
422}
423
424bitwise!(
425 BitAnd,
426 bitand,
427 BitAndAssign,
428 bitand_assign,
429 Op::And,
430 AND,
431 "&",
432 "and",
433 "4",
434 "4",
435 "false",
436 "0",
437 "0",
438 "0",
439 "false"
440);
441bitwise!(
442 BitOr,
443 bitor,
444 BitOrAssign,
445 bitor_assign,
446 Op::Or,
447 OR,
448 "|",
449 "or",
450 "-2",
451 "2",
452 "true",
453 "0x0F, 0xF0",
454 "0x01_FF",
455 "0x01, 0xFF",
456 "true"
457);
458bitwise!(
459 BitXor,
460 bitxor,
461 BitXorAssign,
462 bitxor_assign,
463 Op::Xor,
464 XOR,
465 "^",
466 "exclusive or",
467 "-6",
468 "6",
469 "true",
470 "0x0F, 0xF0",
471 "0x01_FF",
472 "0x01, 0xFF",
473 "true"
474);
475
476impl Not for Number {
477 type Output = Number;
478
479 /// Returns `!self`, every bit of the number in infinite two's complement inverted, which is
480 /// `-self - 1`, in the byte order of `self`, in the shortest form.
481 ///
482 /// The result is built in the vector of `self` when its capacity has room for it, which
483 /// allocates nothing, and otherwise in one new vector of exactly its length; it is at most one
484 /// byte longer. Only the bytes the carry of `+ 1` (or the borrow of `- 1`) passes through
485 /// are written, which for random numbers is the lowest one: a number in the shortest form
486 /// takes constant time.
487 ///
488 /// # Examples
489 ///
490 /// ```
491 /// use a::math::numbers::{ByteOrder, Number};
492 ///
493 /// // As for `i32`: `!0xFF` is `-0x100`, and `!-0x100` is `0xFF`.
494 /// let n = !Number::new_from_i32(0xFF, ByteOrder::BigEndian);
495 /// assert_eq!(n.value, [0x01, 0x00]);
496 /// assert!(n.is_negative());
497 /// let n = !n;
498 /// assert_eq!(n.value, [0xFF]);
499 /// assert!(!n.is_negative());
500 /// ```
501 #[inline]
502 fn not(mut self) -> Number {
503 not_in_place(&mut self);
504 self
505 }
506}
507
508impl Not for &Number {
509 type Output = Number;
510
511 /// Returns `!self`, which is `-self - 1`, in the byte order of `self`, in the shortest form.
512 ///
513 /// The result is built in one new vector of exactly its length; `self` is left as it was.
514 ///
515 /// # Examples
516 ///
517 /// ```
518 /// use a::math::numbers::{ByteOrder, Number};
519 ///
520 /// let a = Number::new_from_i32(-1, ByteOrder::LittleEndian);
521 /// let n = !&a;
522 /// assert_eq!(n.value, [0]);
523 /// assert!(!n.is_negative());
524 /// ```
525 #[inline]
526 fn not(self) -> Number {
527 not_new(self)
528 }
529}
530
531// Small numbers
532
533/// The result of a bitwise operation on two small operands, computed in registers.
534#[derive(Clone, Copy)]
535struct Small {
536 /// The low eight bytes of the magnitude.
537 lo: u64,
538 /// The next eight bytes of the magnitude.
539 hi: u64,
540 /// The length of the result in the shortest form, from 1 to 17: one byte for zero, and 17 for
541 /// a magnitude of `2^128`, whose seventeenth byte is 1 and the others 0.
542 len: usize,
543 /// Whether the result is negative; never for zero.
544 negative: bool,
545}
546
547/// The magnitude `m` with the sign `negative`, or `2^128` when `top` is set, as a [`Small`].
548#[inline(always)]
549fn small_of(m: u128, top: bool, negative: bool) -> Small {
550 Small {
551 lo: m as u64,
552 hi: (m >> 64) as u64,
553 len: if top {
554 SMALL + 1
555 } else {
556 SMALL - (m | 1).leading_zeros() as usize / 8
557 },
558 negative,
559 }
560}
561
562/// `a op b` for small operands, in two's complement on `u128`s: a negative magnitude `x` is
563/// `-x` there, with infinitely many ones above, and a negative result `r` is the magnitude
564/// `2^128 - r`, which is `2^128` itself, 17 bytes, for `r = 0`.
565///
566/// # Safety
567///
568/// Both vectors must hold at most [`SMALL`] bytes.
569#[inline(always)]
570unsafe fn small_result(a: &Number, b: &Number, op: Op) -> Small {
571 // SAFETY: as the caller guarantees.
572 let (x, y) = unsafe {
573 (
574 read_small(&a.value, a.byte_order),
575 read_small(&b.value, b.byte_order),
576 )
577 };
578 // A magnitude of zero is zero, whatever the sign says.
579 let (nx, ny) = (a.negative && x != 0, b.negative && y != 0);
580 let tx = if nx { x.wrapping_neg() } else { x };
581 let ty = if ny { y.wrapping_neg() } else { y };
582 let (r, negative) = match op {
583 Op::And => (tx & ty, nx & ny),
584 Op::Or => (tx | ty, nx | ny),
585 Op::Xor => (tx ^ ty, nx ^ ny),
586 };
587 let m = if negative { r.wrapping_neg() } else { r };
588 small_of(m, negative && r == 0, negative)
589}
590
591/// Writes the small result `s` as the whole value of `v`, in its vector when it has room, in a
592/// new one otherwise.
593#[inline(always)]
594fn put_small(v: &mut Vec<u8>, order: ByteOrder, s: Small) {
595 if v.capacity() >= s.len {
596 // SAFETY: the vector has room for the `len` bytes, from 1 to 17, all of which
597 // `write_small` writes before the length is set.
598 unsafe {
599 write_small(v.as_mut_ptr(), order, s.lo, s.hi, s.len);
600 v.set_len(s.len);
601 }
602 } else {
603 replace_small(v, order, s);
604 }
605}
606
607/// Replaces `v` with one new vector of exactly the small result's length, holding it. Out of
608/// line and cold, so that the small path saves no registers for it.
609#[cold]
610#[inline(never)]
611fn replace_small(v: &mut Vec<u8>, order: ByteOrder, s: Small) {
612 *v = new_small(order, s);
613}
614
615/// The small result `s` in one new vector of exactly its length.
616#[inline(always)]
617fn new_small(order: ByteOrder, s: Small) -> Vec<u8> {
618 let mut v = Vec::with_capacity(s.len);
619 // SAFETY: the new vector has room for the `len` bytes, from 1 to 17, all of which
620 // `write_small` writes before the length is set.
621 unsafe {
622 write_small(v.as_mut_ptr(), order, s.lo, s.hi, s.len);
623 v.set_len(s.len);
624 }
625 v
626}
627
628/// The small result `s` as a number in one new vector, in the byte order `order`. Out of line,
629/// so that the small path of `&a op &b` saves no registers for the allocation.
630#[inline(never)]
631fn small_number(order: ByteOrder, s: Small) -> Number {
632 Number {
633 value: new_small(order, s),
634 negative: s.negative,
635 byte_order: order,
636 }
637}
638
639// Operands that are not negative
640
641/// `a op b` written over `a`, for `a` and `b` that are not negative (as their signs say), in the
642/// same byte order, of which at least one has more than 16 bytes, when `a`'s vector has room for
643/// the longest the result can be, and big-endian, the result's positions are those of `a`:
644/// `op` is the operation on the magnitudes' bytes, known here, with no borrow or carry, so the
645/// kernel runs straight over the bytes of the shorter magnitude, and the longer one's top bytes
646/// follow for `|` and `^`. The length of the result is the longer magnitude's then, and otherwise
647/// found from the top down, one read for random operands (of the operands big-endian, of the
648/// result little-endian); big-endian, a shorter result is moved to the start of the vector. Returns whether it did, with nothing written
649/// otherwise; zero operands are left to the general path.
650///
651/// Measured on an Apple M4 Max over operands in the level-1 cache, `a ^= &b` of 24, 64 and 128
652/// bytes took 13, 16 and 17 cycles so, against 17, 28 and 28 through the paths for any signs, and
653/// GMP 6.3's `mpz_xor(a, a, b)` 11, 13 and 20.
654#[inline(always)]
655fn plus_over<const OP: u8>(a: &mut Number, b: &Number) -> bool {
656 if a.negative | b.negative || a.byte_order != b.byte_order {
657 return false;
658 }
659 if a.byte_order == ByteOrder::BigEndian {
660 plus_over_in::<OP, true>(&mut a.value, &b.value)
661 } else {
662 plus_over_in::<OP, false>(&mut a.value, &b.value)
663 }
664}
665
666/// [`plus_over`] for the layout `BE`.
667#[inline(never)]
668fn plus_over_in<const OP: u8, const BE: bool>(v: &mut Vec<u8>, y: &[u8]) -> bool {
669 let n = v.len();
670 let (lx, ly) = (sig_len::<BE>(v), sig_len::<BE>(y));
671 let (long, short) = (lx.max(ly), lx.min(ly));
672 // The bound of the result's length, which is its length but for `&`, and `^` of magnitudes
673 // of the same length.
674 let u = if OP == AND { short } else { long };
675 if short == 0 || v.capacity() < u || (BE && u != n) {
676 return false;
677 }
678 let ye = end::<BE>(y);
679 // The length of a result that can be shorter than `u`: big-endian, from the top of the
680 // operands down, before anything is written; little-endian, read back from the top of the
681 // result. Read back big-endian, it waited for the kernel's stores (measured on an Apple M4
682 // Max, a big-endian `^=` of 40 to 64 bytes took 30 to 34 cycles so, against 19 to 20), and
683 // read first little-endian, it took two cycles more than read back.
684 let cut = OP == AND || (OP == XOR && lx == ly);
685 let first = if cut && BE {
686 // SAFETY: the positions below `short` are significant in both magnitudes.
687 unsafe { highest::<BE, BE>(OP, end::<BE>(v), ye, 0, short) }.unwrap_or(1)
688 } else {
689 long
690 };
691 let base = v.as_mut_ptr();
692 // SAFETY: the reads are of the significant bytes of each magnitude, the writes of the
693 // `u <= capacity` bytes of `v`, at the positions of `x` (big-endian, `x` ends at `n = u`),
694 // each block of `x` read before it is written over at the same positions.
695 unsafe {
696 let dst = if BE { base.add(n) } else { base };
697 kernels::logic::<OP, false, false>(
698 at_mut::<BE>(dst, 0, short),
699 at::<BE>(dst, 0, short),
700 at::<BE>(ye, 0, short),
701 short,
702 );
703 let len = if cut && BE {
704 if first < u {
705 ptr::copy(base.add(u - first), base, first);
706 }
707 first
708 } else if cut {
709 highest_of::<BE>(dst, u)
710 } else {
711 if ly > lx {
712 let k = long - short;
713 ptr::copy_nonoverlapping(at::<BE>(ye, short, k), at_mut::<BE>(dst, short, k), k);
714 }
715 long
716 };
717 v.set_len(len);
718 }
719 true
720}
721
722/// The length up to the highest nonzero byte of the `u >= 1` bytes at the least significant end
723/// `end` in the layout `BE`, or 1 when they are all zero: from the top down, eight at a time.
724///
725/// # Safety
726///
727/// The `u` bytes must be valid for reads.
728#[inline(always)]
729unsafe fn highest_of<const BE: bool>(end: *const u8, u: usize) -> usize {
730 let mut q = u;
731 // SAFETY: every read is of positions below `u`.
732 unsafe {
733 while q >= 8 {
734 let w = load::<BE>(end, q - 8);
735 if w != 0 {
736 return q - w.leading_zeros() as usize / 8;
737 }
738 q -= 8;
739 }
740 while q > 1 && get::<BE>(end, q - 1) == 0 {
741 q -= 1;
742 }
743 q.max(1)
744 }
745}
746
747/// `a op b` in one new vector of exactly its length, for `a` and `b` that are not negative, in
748/// the same byte order, of which at least one has more than 16 bytes, as [`plus_over`] computes
749/// it, with the length found first: the longer magnitude's, or from the top down for `&`, and
750/// `^` of magnitudes of the same length. `None` for the other operands, and zero ones.
751#[inline(always)]
752fn plus_new<const OP: u8>(a: &Number, b: &Number) -> Option<Number> {
753 if a.negative | b.negative || a.byte_order != b.byte_order {
754 return None;
755 }
756 let value = if a.byte_order == ByteOrder::BigEndian {
757 plus_new_in::<OP, true>(&a.value, &b.value)?
758 } else {
759 plus_new_in::<OP, false>(&a.value, &b.value)?
760 };
761 Some(Number {
762 value,
763 negative: false,
764 byte_order: a.byte_order,
765 })
766}
767
768/// [`plus_new`] for the layout `BE`.
769#[inline(never)]
770fn plus_new_in<const OP: u8, const BE: bool>(x: &[u8], y: &[u8]) -> Option<Vec<u8>> {
771 let (lx, ly) = (sig_len::<BE>(x), sig_len::<BE>(y));
772 let (long, short) = (lx.max(ly), lx.min(ly));
773 let (xe, ye) = (end::<BE>(x), end::<BE>(y));
774 let len = if OP == AND || (OP == XOR && lx == ly) {
775 // SAFETY: the positions below `short` are significant in both magnitudes.
776 unsafe { highest::<BE, BE>(OP, xe, ye, 0, short)? }
777 } else if short > 0 {
778 long
779 } else {
780 return None;
781 };
782 let mut v = Vec::<u8>::with_capacity(len);
783 // SAFETY: the new vector has room for the `len` bytes, all of which are written: positions
784 // below `min(short, len)` by the kernel, the others, for `|` and `^`, from the longer
785 // magnitude.
786 unsafe {
787 let base = v.as_mut_ptr();
788 let dst = if BE { base.add(len) } else { base };
789 let k = short.min(len);
790 kernels::logic::<OP, false, false>(
791 at_mut::<BE>(dst, 0, k),
792 at::<BE>(xe, 0, k),
793 at::<BE>(ye, 0, k),
794 k,
795 );
796 if len > short {
797 let (from, k) = (if lx > ly { xe } else { ye }, len - short);
798 ptr::copy_nonoverlapping(at::<BE>(from, short, k), at_mut::<BE>(dst, short, k), k);
799 }
800 v.set_len(len);
801 }
802 Some(v)
803}
804
805// Operands of up to 64 bytes
806
807/// The result of a bitwise operation on two operands of up to 64 bytes, computed in registers.
808struct Medium {
809 /// The limbs of the magnitude, the least significant first: up to eight, then the ninth,
810 /// which is 1 for a magnitude of `2^(64 L)`, then zeros.
811 limbs: [u64; 9],
812 /// The length of the result in the shortest form: one byte for zero.
813 len: usize,
814 /// The number `L` of limbs the operands were read as, when the result is at least
815 /// `8 (L - 1)` bytes long, with its top eight positions in `top`; zero otherwise.
816 long: usize,
817 /// The eight positions of the result that end at its top, when `long` is set.
818 top: u64,
819 /// Whether the result is negative; never for zero.
820 negative: bool,
821}
822
823/// `a op b` for operands of at most 64 bytes, `op` one of [`AND`], [`OR`] and [`XOR`], by the
824/// number of limbs of the longer vector, from 3 to 8.
825///
826/// The limit is the addition's medium path's, whose reading of limbs this shares. Measured on an
827/// Apple M4 Max with negative operands, `a &= &b` and `a ^= &b` of 40 and 48 bytes took 28 to 32
828/// cycles in registers, against 36 to 40 through the general path; at 64 bytes the two are about
829/// even (36 to 41 cycles against 35 to 48).
830///
831/// # Safety
832///
833/// Both vectors must hold at most [`MEDIUM`](super::add::MEDIUM) bytes.
834#[inline(always)]
835unsafe fn medium_result<const OP: u8>(a: &Number, b: &Number) -> Medium {
836 // SAFETY: as the caller guarantees, the vectors hold at most `8 L` bytes for the `L` chosen.
837 unsafe {
838 match a.value.len().max(b.value.len()).div_ceil(8) {
839 ..=3 => medium_of::<OP, 3>(a, b),
840 4 => medium_of::<OP, 4>(a, b),
841 5 => medium_of::<OP, 5>(a, b),
842 6 => medium_of::<OP, 6>(a, b),
843 7 => medium_of::<OP, 7>(a, b),
844 _ => medium_of::<OP, 8>(a, b),
845 }
846 }
847}
848
849/// [`medium_result`] for vectors of at most `L` limbs: the magnitudes read into `L` limbs each as
850/// the addition reads them, turned into two's complement where they are negative (`!x + 1`, one
851/// chain of carries, the limbs above the vector all ones), `op` on the limbs, and a negative
852/// result turned back into its magnitude the same way, all without a branch.
853///
854/// # Safety
855///
856/// Both vectors must hold at most `8 L` bytes.
857#[inline(never)]
858unsafe fn medium_of<const OP: u8, const L: usize>(a: &Number, b: &Number) -> Medium {
859 // SAFETY: as the caller guarantees.
860 let (x, y) = unsafe {
861 (
862 read_limbs::<L>(&a.value, a.byte_order),
863 read_limbs::<L>(&b.value, b.byte_order),
864 )
865 };
866 let nonzero = |v: &[u64; 9]| v.iter().take(L).fold(0, |o, &l| o | l) != 0;
867 // A magnitude of zero is zero, whatever the sign says.
868 let (nx, ny) = (a.negative && nonzero(&x), b.negative && nonzero(&y));
869 let negative = match OP {
870 AND => nx & ny,
871 OR => nx | ny,
872 _ => nx ^ ny,
873 };
874 let (mx, my, mr) = (
875 0u64.wrapping_sub(u64::from(nx)),
876 0u64.wrapping_sub(u64::from(ny)),
877 0u64.wrapping_sub(u64::from(negative)),
878 );
879 let (mut cx, mut cy, mut cr) = (nx, ny, negative);
880 let mut limbs = [0u64; 9];
881 for i in 0..L {
882 let (tx, c) = (x[i] ^ mx).overflowing_add(u64::from(cx));
883 cx = c;
884 let (ty, c) = (y[i] ^ my).overflowing_add(u64::from(cy));
885 cy = c;
886 let r = match OP {
887 AND => tx & ty,
888 OR => tx | ty,
889 _ => tx ^ ty,
890 };
891 let (m, c) = (r ^ mr).overflowing_add(u64::from(cr));
892 cr = c;
893 limbs[i] = m;
894 }
895 // Above the limbs, the result is `mr` in two's complement, and its magnitude zero, but for
896 // the carry out of the top limb: a negative result that is zero in all `L` limbs is
897 // `-2^(64 L)`.
898 limbs[L] = u64::from(cr);
899 if long::<L>(&limbs) {
900 // The length and the top eight positions without a branch, as the addition finds them:
901 // whether `&` or `|` of operands of a sign each loses a top byte is a coin toss.
902 let (len, top) = top_of::<L>(&limbs);
903 return Medium {
904 limbs,
905 len,
906 long: L,
907 top,
908 negative,
909 };
910 }
911 let mut t = L;
912 while t > 0 && limbs[t] == 0 {
913 t -= 1;
914 }
915 Medium {
916 limbs,
917 len: 8 * t + 8 - (limbs[t] | 1).leading_zeros() as usize / 8,
918 long: 0,
919 top: 0,
920 negative,
921 }
922}
923
924/// Writes the medium result `m` over the first `m.len` bytes at `p`, in the layout of `order`.
925///
926/// A result of at least `8 (L - 1)` bytes, as for operands of `L` limbs that do not nearly
927/// cancel, is written by stores chosen by `L`, not by its length, which `&` and `|` make a coin
928/// toss: limbs `0..L - 1` at their places, limb `L - 1` at its place or, for a result shorter
929/// than `8 L` bytes, below the top eight positions, and then those, as the addition writes a
930/// medium sum. Measured on an Apple M4 Max, `a &= &b` of a positive `a` and a negative `b` of 24
931/// and 48 bytes took 20 and 29 cycles so, against 25 and 32 with stores chosen by the length. Otherwise: up to 16 bytes as the addition writes a short sum; beyond, the whole
932/// limbs, then the eight positions that end at the top, over the limb below.
933///
934/// # Safety
935///
936/// `p` must be valid for writing `m.len` bytes.
937#[inline(always)]
938unsafe fn write_medium(p: *mut u8, order: ByteOrder, m: &Medium) {
939 let (r, len) = (&m.limbs, m.len);
940 let be = order == ByteOrder::BigEndian;
941 // SAFETY: every write lies inside the `len` bytes at `p`: a long result has `len >= 8 (L - 1)`
942 // bytes and `L >= 3`, so `len >= 16`.
943 unsafe {
944 if m.long > 0 {
945 let l = m.long;
946 let c = (8 * (l - 1)).min(len - 8);
947 for (i, limb) in r.iter().enumerate().take(l - 1) {
948 if be {
949 write(p.add(len - 8 - 8 * i), limb.to_be_bytes());
950 } else {
951 write(p.add(8 * i), limb.to_le_bytes());
952 }
953 }
954 if be {
955 write(p.add(len - 8 - c), r[l - 1].to_be_bytes());
956 write(p, m.top.to_be_bytes());
957 } else {
958 write(p.add(c), r[l - 1].to_le_bytes());
959 write(p.add(len - 8), m.top.to_le_bytes());
960 }
961 return;
962 }
963 if len <= SMALL {
964 write_small(p, order, r[0], r[1], len);
965 return;
966 }
967 let (full, rem) = (len / 8, len % 8);
968 for (i, limb) in r.iter().enumerate().take(full) {
969 if be {
970 write(p.add(len - 8 - 8 * i), limb.to_be_bytes());
971 } else {
972 write(p.add(8 * i), limb.to_le_bytes());
973 }
974 }
975 if rem > 0 {
976 let k = 8 * rem as u32;
977 let top = (r[full - 1] >> k) | (r[full] << (64 - k));
978 if be {
979 write(p, top.to_be_bytes());
980 } else {
981 write(p.add(len - 8), top.to_le_bytes());
982 }
983 }
984 }
985}
986
987/// Writes the medium result `m` as the whole value of `v`, in its vector when it has room, in a
988/// new one otherwise.
989#[inline(always)]
990fn put_medium(v: &mut Vec<u8>, order: ByteOrder, m: &Medium) {
991 if v.capacity() < m.len {
992 *v = Vec::with_capacity(m.len);
993 }
994 // SAFETY: the vector has room for the `len` bytes, all of which are written before the length
995 // is set.
996 unsafe {
997 write_medium(v.as_mut_ptr(), order, m);
998 v.set_len(m.len);
999 }
1000}
1001
1002/// The medium result `m` as a number in one new vector, in the byte order `order`.
1003#[inline(never)]
1004fn medium_number(order: ByteOrder, m: &Medium) -> Number {
1005 let mut value = Vec::new();
1006 put_medium(&mut value, order, m);
1007 Number {
1008 value,
1009 negative: m.negative,
1010 byte_order: order,
1011 }
1012}
1013
1014// The general path: operands of more than 64 bytes, out of line, so that the small path saves no
1015// registers for it.
1016
1017/// `a op b` for borrowed operands, of which at least one has more than 64 bytes.
1018#[inline(never)]
1019fn ref_ref(a: &Number, b: &Number, op: Op) -> Number {
1020 let plan = plan(a, b, op);
1021 Number {
1022 value: new_result(a, b, &plan),
1023 negative: plan.negative,
1024 byte_order: a.byte_order,
1025 }
1026}
1027
1028/// `a op b` for a borrowed `a` and an owned `b`, of which at least one has more than 64 bytes.
1029/// The result takes the vector of `b` when it is built there, leaving `b` an empty one; the
1030/// caller drops `b` either way.
1031#[inline(never)]
1032fn ref_value(a: &Number, b: &mut Number, op: Op) -> Number {
1033 let order = a.byte_order;
1034 // The operations are symmetric: `b op a` over `b`, when it is in the result's byte order.
1035 if b.byte_order == order
1036 && let Some(negative) = over(&mut b.value, order, b.negative, a, op)
1037 {
1038 return Number {
1039 value: mem::take(&mut b.value),
1040 negative,
1041 byte_order: order,
1042 };
1043 }
1044 let plan = plan(a, b, op);
1045 let value = if b.value.capacity() >= plan.len {
1046 if b.byte_order != order {
1047 b.value.reverse();
1048 b.byte_order = order;
1049 }
1050 // SAFETY: the vector of `b`, in the byte order of the result now, has room for it, and the
1051 // plan with the operands swapped is that of `b` and `a`.
1052 unsafe { in_vector(&mut b.value, order, a, &plan.swapped()) };
1053 mem::take(&mut b.value)
1054 } else {
1055 new_result(a, b, &plan)
1056 };
1057 Number {
1058 value,
1059 negative: plan.negative,
1060 byte_order: order,
1061 }
1062}
1063
1064/// `a op= b` for a borrowed `b`, where at least one of them has more than 64 bytes.
1065#[inline(never)]
1066fn assign_ref(a: &mut Number, b: &Number, op: Op) {
1067 if let Some(negative) = over(&mut a.value, a.byte_order, a.negative, b, op) {
1068 a.negative = negative;
1069 return;
1070 }
1071 let plan = plan(a, b, op);
1072 if a.value.capacity() >= plan.len {
1073 // SAFETY: the vector of `a` has room for the result, and the plan is that of `a` and `b`.
1074 unsafe { in_vector(&mut a.value, a.byte_order, b, &plan) };
1075 } else {
1076 a.value = new_result(a, b, &plan);
1077 }
1078 a.negative = plan.negative;
1079}
1080
1081/// `a op= b` for an owned `b`, where at least one of them has more than 64 bytes. When the
1082/// result is built in the vector of `b`, the vector of `a` goes to `b`; the caller drops `b`
1083/// either way.
1084#[inline(never)]
1085fn assign_value(a: &mut Number, b: &mut Number, op: Op) {
1086 let order = a.byte_order;
1087 if let Some(negative) = over(&mut a.value, order, a.negative, b, op) {
1088 a.negative = negative;
1089 return;
1090 }
1091 let plan = plan(a, b, op);
1092 if a.value.capacity() >= plan.len {
1093 // SAFETY: the vector of `a` has room for the result, and the plan is that of `a` and `b`.
1094 unsafe { in_vector(&mut a.value, order, b, &plan) };
1095 } else if b.value.capacity() >= plan.len {
1096 if b.byte_order != order {
1097 b.value.reverse();
1098 b.byte_order = order;
1099 }
1100 // SAFETY: the vector of `b`, in the byte order of the result now, has room for it, and the
1101 // plan with the operands swapped is that of `b` and `a`.
1102 unsafe { in_vector(&mut b.value, order, a, &plan.swapped()) };
1103 mem::swap(&mut a.value, &mut b.value);
1104 } else {
1105 a.value = new_result(a, b, &plan);
1106 }
1107 a.negative = plan.negative;
1108}
1109
1110// Over an operand
1111
1112/// `x op y` written over `x`, the magnitude in `v` in the layout `order` with the sign
1113/// `negative_x`, as the general path's first try, when it is simple: `v` has room for the result
1114/// in the shortest form, which big-endian also ends where `x` does, and a borrow or a carry runs
1115/// through one limb at most, as for random operands. Then the plan is cut short: the length of the
1116/// result is the longer magnitude's when the result takes its top bytes, and otherwise found from
1117/// the top down, one read for random operands; the head is one limb, computed and written first;
1118/// and the rest is one call to the kernel and a copy. Returns the sign of the result, or `None`,
1119/// with nothing written, for the cases left to the plan.
1120///
1121/// Measured on an Apple M4 Max over operands in the level-1 cache, the plan and its second pass
1122/// over the head cost a `^=` of 256 bytes about 340 instructions a call, 57 cycles; this path,
1123/// 250 instructions and 35 to 38 cycles.
1124#[inline]
1125fn over(v: &mut Vec<u8>, order: ByteOrder, negative_x: bool, y: &Number, op: Op) -> Option<bool> {
1126 // SAFETY: `v` and `y` are a valid vector and number.
1127 unsafe {
1128 match (
1129 order == ByteOrder::BigEndian,
1130 y.byte_order == ByteOrder::BigEndian,
1131 ) {
1132 (true, true) => over_in::<true, true>(v, negative_x, y, op),
1133 (true, false) => over_in::<true, false>(v, negative_x, y, op),
1134 (false, true) => over_in::<false, true>(v, negative_x, y, op),
1135 (false, false) => over_in::<false, false>(v, negative_x, y, op),
1136 }
1137 }
1138}
1139
1140/// [`over`] for `x` in the layout `XBE` and `y` in `YBE`.
1141///
1142/// # Safety
1143///
1144/// None beyond the validity of `v` and `y`; unsafe for the raw reads and writes inside.
1145#[inline(never)]
1146unsafe fn over_in<const XBE: bool, const YBE: bool>(
1147 v: &mut Vec<u8>,
1148 negative_x: bool,
1149 y: &Number,
1150 op: Op,
1151) -> Option<bool> {
1152 let n = v.len();
1153 let lx = sig_len::<XBE>(v);
1154 let ly = sig_len::<YBE>(&y.value);
1155 let (nx, ny) = (negative_x && lx > 0, y.negative && ly > 0);
1156 let (g, negative) = select(op, nx, ny);
1157 let tail = tail_of(g, lx, ly);
1158 let (long, short) = (lx.max(ly), lx.min(ly));
1159 let x = end::<XBE>(v);
1160 let ye = end::<YBE>(&y.value);
1161 // SAFETY: the reads are of the significant bytes of each magnitude.
1162 let (head, lo) = unsafe {
1163 if nx | ny | negative {
1164 let mut flags = Flags {
1165 x: nx,
1166 y: ny,
1167 carry: negative,
1168 };
1169 let w = flags.next(g, limb::<XBE>(x, lx, 0), limb::<YBE>(ye, ly, 0));
1170 if flags.running() || short < 8 {
1171 return None;
1172 }
1173 (w, 8)
1174 } else {
1175 (0, 0)
1176 }
1177 };
1178 let len = if tail != Tail::Zero {
1179 long
1180 } else {
1181 // SAFETY: the positions below `short` are significant in both magnitudes.
1182 match unsafe { highest::<XBE, YBE>(g, x, ye, lo, short) } {
1183 Some(len) => len,
1184 None if lo == 0 => return None,
1185 // The head's limb, alone.
1186 None => 8 - (head | 1).leading_zeros() as usize / 8,
1187 }
1188 };
1189 if v.capacity() < len || (XBE && len != n) {
1190 return None;
1191 }
1192 let base = v.as_mut_ptr();
1193 // SAFETY: the result ends where `x` does, big-endian, as `len == n`; the reads are of the
1194 // significant bytes of each magnitude, the writes of the `len <= capacity` bytes of `v`, each
1195 // limb or block of `x` read before it is written over at the same positions. The bulk ends at
1196 // `len` when that is below `short`, and the head is at most `len` long but for its zero bytes.
1197 unsafe {
1198 let dst = if XBE { base.add(n) } else { base };
1199 let x = dst.cast_const();
1200 if lo > 0 {
1201 put_limb::<XBE>(dst, len, 0, head);
1202 }
1203 let bulk = short.min(len);
1204 if bulk > lo {
1205 let k = bulk - lo;
1206 logic::<false>(
1207 g,
1208 XBE != YBE,
1209 at_mut::<XBE>(dst, lo, k),
1210 at::<XBE>(x, lo, k),
1211 at::<YBE>(ye, lo, k),
1212 k,
1213 );
1214 }
1215 if tail == Tail::Y {
1216 let k = long - short;
1217 if XBE != YBE {
1218 kernels::copy_reversed(at_mut::<XBE>(dst, short, k), at::<YBE>(ye, short, k), k);
1219 } else {
1220 ptr::copy_nonoverlapping(at::<YBE>(ye, short, k), at_mut::<XBE>(dst, short, k), k);
1221 }
1222 }
1223 v.set_len(len);
1224 }
1225 Some(negative)
1226}
1227
1228/// What the bytes of the result of `g` above the shorter magnitude are, for magnitudes of `lx`
1229/// and `ly` significant bytes: `g(x, 0)` is `x` for `|`, `^` and `x & !y`, and zero for the
1230/// others; `g(0, y)` likewise.
1231#[inline(always)]
1232fn tail_of(g: u8, lx: usize, ly: usize) -> Tail {
1233 // Bit `g` of each mask: whether `g` keeps the longer `x`, or the longer `y`.
1234 const KEEPS_X: u8 = 1 << OR | 1 << XOR | 1 << AND_NOT;
1235 const KEEPS_Y: u8 = 1 << OR | 1 << XOR | 1 << NOT_AND;
1236 if lx > ly && KEEPS_X >> g & 1 != 0 {
1237 Tail::X
1238 } else if ly > lx && KEEPS_Y >> g & 1 != 0 {
1239 Tail::Y
1240 } else {
1241 Tail::Zero
1242 }
1243}
1244
1245/// The significant length of the magnitude in `v` in the layout `BE`: its length when its top
1246/// byte is not zero, as in the shortest form, at the cost of one read, and otherwise as
1247/// [`significant_len`] finds it.
1248#[inline(always)]
1249fn sig_len<const BE: bool>(v: &[u8]) -> usize {
1250 let n = v.len();
1251 // SAFETY: the top byte is read when there is one.
1252 if n > 0 && unsafe { get::<BE>(end::<BE>(v), n - 1) } != 0 {
1253 n
1254 } else {
1255 significant_len::<BE>(v)
1256 }
1257}
1258
1259// Planning
1260
1261/// What the bytes of the result above the shorter magnitude are.
1262#[derive(Clone, Copy, PartialEq, Eq)]
1263enum Tail {
1264 /// Zero: the result ends below them.
1265 Zero,
1266 /// Those of `x`.
1267 X,
1268 /// Those of `y`.
1269 Y,
1270}
1271
1272/// Everything about the result of a bitwise operation on `x` and `y` but its bytes.
1273#[derive(Clone, Copy)]
1274struct Plan {
1275 /// The operation on the bytes of the magnitudes (or of the magnitudes less one).
1276 g: u8,
1277 /// The significant length of `x`.
1278 lx: usize,
1279 /// The significant length of `y`.
1280 ly: usize,
1281 /// Whether `x` is negative and not zero: `X - 1` is taken instead of `X`.
1282 nx: bool,
1283 /// Whether `y` is negative and not zero.
1284 ny: bool,
1285 /// Whether the result is negative: one is added to what `g` gives.
1286 negative: bool,
1287 /// The number of limbs at the low end through which a borrow or the carry runs, worked out
1288 /// one at a time; above them, each byte of the result is `g` of the operands' bytes.
1289 head: usize,
1290 /// The bytes of the result above the shorter magnitude.
1291 tail: Tail,
1292 /// The length of the result in the shortest form: one byte for zero.
1293 len: usize,
1294}
1295
1296impl Plan {
1297 /// The plan of the same operation with `x` and `y` swapped.
1298 #[inline(always)]
1299 fn swapped(&self) -> Plan {
1300 Plan {
1301 g: match self.g {
1302 AND_NOT => NOT_AND,
1303 NOT_AND => AND_NOT,
1304 g => g,
1305 },
1306 lx: self.ly,
1307 ly: self.lx,
1308 nx: self.ny,
1309 ny: self.nx,
1310 tail: match self.tail {
1311 Tail::X => Tail::Y,
1312 Tail::Y => Tail::X,
1313 Tail::Zero => Tail::Zero,
1314 },
1315 ..*self
1316 }
1317 }
1318}
1319
1320/// The borrows of `X - 1` and `Y - 1` and the carry of the result's `+ 1`, from one limb to the
1321/// next.
1322struct Flags {
1323 x: bool,
1324 y: bool,
1325 carry: bool,
1326}
1327
1328impl Flags {
1329 /// The limb of the result from the limbs `x` and `y` of the magnitudes at the same position,
1330 /// and the flags for the next limb. A borrow out of `X - 1` stops at the lowest nonzero limb
1331 /// of `X`, and the carry at the lowest limb of `g` that is not all ones.
1332 #[inline(always)]
1333 fn next(&mut self, g: u8, x: u64, y: u64) -> u64 {
1334 let xm = x.wrapping_sub(u64::from(self.x));
1335 self.x &= x == 0;
1336 let ym = y.wrapping_sub(u64::from(self.y));
1337 self.y &= y == 0;
1338 let m = apply(g, xm, ym);
1339 let r = m.wrapping_add(u64::from(self.carry));
1340 self.carry &= m == u64::MAX;
1341 r
1342 }
1343
1344 /// Whether a borrow or the carry is still running.
1345 #[inline(always)]
1346 fn running(&self) -> bool {
1347 self.x | self.y | self.carry
1348 }
1349}
1350
1351/// The plan of `a op b`, with `x` = `a` and `y` = `b`.
1352#[inline]
1353fn plan(a: &Number, b: &Number, op: Op) -> Plan {
1354 match (
1355 a.byte_order == ByteOrder::BigEndian,
1356 b.byte_order == ByteOrder::BigEndian,
1357 ) {
1358 (true, true) => plan_in::<true, true>(a, b, op),
1359 (true, false) => plan_in::<true, false>(a, b, op),
1360 (false, true) => plan_in::<false, true>(a, b, op),
1361 (false, false) => plan_in::<false, false>(a, b, op),
1362 }
1363}
1364
1365/// [`plan`] for `a` in the layout `XBE` and `b` in `YBE`.
1366#[inline(always)]
1367fn plan_in<const XBE: bool, const YBE: bool>(a: &Number, b: &Number, op: Op) -> Plan {
1368 let lx = sig_len::<XBE>(&a.value);
1369 let ly = sig_len::<YBE>(&b.value);
1370 let (nx, ny) = (a.negative && lx > 0, b.negative && ly > 0);
1371 let (g, negative) = select(op, nx, ny);
1372 let tail = tail_of(g, lx, ly);
1373 let (xe, ye) = (end::<XBE>(&a.value), end::<YBE>(&b.value));
1374 // The head, and the length of its part of the result.
1375 let (mut head, mut top) = (0, 0);
1376 if nx | ny | negative {
1377 let mut flags = Flags {
1378 x: nx,
1379 y: ny,
1380 carry: negative,
1381 };
1382 loop {
1383 // SAFETY: `limb` reads the significant bytes of each magnitude only. The loop ends:
1384 // past both magnitudes, whose borrows end at their lowest nonzero byte, `g(0, 0)` is
1385 // zero and ends the carry.
1386 let r = unsafe { flags.next(g, limb::<XBE>(xe, lx, head), limb::<YBE>(ye, ly, head)) };
1387 if r != 0 {
1388 top = 8 * head + 8 - r.leading_zeros() as usize / 8;
1389 }
1390 head += 1;
1391 if !flags.running() {
1392 break;
1393 }
1394 }
1395 }
1396 let (long, short) = (lx.max(ly), lx.min(ly));
1397 let len = if 8 * head >= long {
1398 top.max(1)
1399 } else if tail != Tail::Zero {
1400 // The top byte of the longer magnitude, which is not zero.
1401 long
1402 } else {
1403 // SAFETY: the positions below `short` are significant in both magnitudes.
1404 unsafe { highest::<XBE, YBE>(g, xe, ye, 8 * head, short) }.unwrap_or(top.max(1))
1405 };
1406 Plan {
1407 g,
1408 lx,
1409 ly,
1410 nx,
1411 ny,
1412 negative,
1413 head,
1414 tail,
1415 len,
1416 }
1417}
1418
1419/// The length up to the highest nonzero byte of `g(x, y)` at positions `lo..hi`, or `None` when
1420/// they are all zero: from the top down, eight positions at a time, so that for random operands
1421/// the first read decides.
1422///
1423/// # Safety
1424///
1425/// Positions `lo..hi` of the magnitudes at the least significant ends `x` (layout `XBE`) and `y`
1426/// (layout `YBE`) must be valid for reads.
1427#[inline(always)]
1428unsafe fn highest<const XBE: bool, const YBE: bool>(
1429 g: u8,
1430 x: *const u8,
1431 y: *const u8,
1432 lo: usize,
1433 hi: usize,
1434) -> Option<usize> {
1435 let mut q = hi;
1436 // SAFETY: every read is of positions from `lo` to `hi`.
1437 unsafe {
1438 while q >= lo + 8 {
1439 let m = apply(g, load::<XBE>(x, q - 8), load::<YBE>(y, q - 8));
1440 if m != 0 {
1441 return Some(q - m.leading_zeros() as usize / 8);
1442 }
1443 q -= 8;
1444 }
1445 while q > lo {
1446 let m = apply(
1447 g,
1448 u64::from(get::<XBE>(x, q - 1)),
1449 u64::from(get::<YBE>(y, q - 1)),
1450 );
1451 if m as u8 != 0 {
1452 return Some(q);
1453 }
1454 q -= 1;
1455 }
1456 }
1457 None
1458}
1459
1460// Building the result
1461
1462/// Where the result is written, relative to the magnitude `x` it is computed from.
1463#[derive(Clone, Copy, PartialEq, Eq)]
1464enum Place {
1465 /// In a vector of its own.
1466 New,
1467 /// Over `x`, at the same positions.
1468 Same,
1469 /// Over `x`, `d > 0` bytes further on in memory: a big-endian result longer than the vector
1470 /// of `x`, whose least significant byte is at the end.
1471 Above,
1472 /// Over `x`, `d > 0` bytes further back in memory: a big-endian result shorter than the vector
1473 /// of `x`.
1474 Below,
1475}
1476
1477/// The limbs of the head a result written [`Place::Below`] its operand holds back until the rest
1478/// is written: as many as random operands need, one, and more. A longer head moves the operand
1479/// first.
1480const HELD: usize = 4;
1481
1482/// The result of `plan` in one new vector of exactly its length, from `x` = `a` and `y` = `b`.
1483fn new_result(a: &Number, b: &Number, plan: &Plan) -> Vec<u8> {
1484 let mut v = Vec::<u8>::with_capacity(plan.len);
1485 let p = v.as_mut_ptr();
1486 // SAFETY: the new vector has room for the `len` bytes of the result, all of which `compute`
1487 // writes, apart from the operands.
1488 unsafe {
1489 match (
1490 a.byte_order == ByteOrder::BigEndian,
1491 b.byte_order == ByteOrder::BigEndian,
1492 ) {
1493 (true, true) => compute::<true, true>(
1494 p.add(plan.len),
1495 end::<true>(&a.value),
1496 end::<true>(&b.value),
1497 plan,
1498 Place::New,
1499 ),
1500 (true, false) => compute::<true, false>(
1501 p.add(plan.len),
1502 end::<true>(&a.value),
1503 end::<false>(&b.value),
1504 plan,
1505 Place::New,
1506 ),
1507 (false, true) => compute::<false, true>(
1508 p,
1509 end::<false>(&a.value),
1510 end::<true>(&b.value),
1511 plan,
1512 Place::New,
1513 ),
1514 (false, false) => compute::<false, false>(
1515 p,
1516 end::<false>(&a.value),
1517 end::<false>(&b.value),
1518 plan,
1519 Place::New,
1520 ),
1521 }
1522 v.set_len(plan.len);
1523 }
1524 v
1525}
1526
1527/// Computes the result of `plan` over `x`, the magnitude in `v` in the layout `order`, and `y`,
1528/// and sets the length of `v` to it.
1529///
1530/// # Safety
1531///
1532/// The capacity of `v` must be at least the length of the result, and the plan that of `x` and
1533/// `y`.
1534#[inline(always)]
1535unsafe fn in_vector(v: &mut Vec<u8>, order: ByteOrder, y: &Number, plan: &Plan) {
1536 let (n, len) = (v.len(), plan.len);
1537 let base = v.as_mut_ptr();
1538 // SAFETY: as the caller guarantees: the vector has room for the `len` bytes, all of which
1539 // `compute` writes. Big-endian, `x` ends at `n` and the result at `len`.
1540 unsafe {
1541 if order == ByteOrder::BigEndian {
1542 let place = match len.cmp(&n) {
1543 core::cmp::Ordering::Equal => Place::Same,
1544 core::cmp::Ordering::Greater => Place::Above,
1545 core::cmp::Ordering::Less => Place::Below,
1546 };
1547 let (dst, x) = (base.add(len), base.add(n).cast_const());
1548 if y.byte_order == ByteOrder::BigEndian {
1549 compute::<true, true>(dst, x, end::<true>(&y.value), plan, place);
1550 } else {
1551 compute::<true, false>(dst, x, end::<false>(&y.value), plan, place);
1552 }
1553 } else if y.byte_order == ByteOrder::BigEndian {
1554 compute::<false, true>(base, base, end::<true>(&y.value), plan, Place::Same);
1555 } else {
1556 compute::<false, false>(base, base, end::<false>(&y.value), plan, Place::Same);
1557 }
1558 v.set_len(len);
1559 }
1560}
1561
1562/// Writes the `len` bytes of the result of `plan` at the least significant end `dst` in the
1563/// layout `XBE`, from the magnitudes at the least significant ends `x` (layout `XBE`) and `y`
1564/// (`YBE`), with `dst` placed as `place` says relative to `x`: the head limb by limb, the bytes
1565/// above it up to the shorter magnitude by the kernels, and the tail copied.
1566///
1567/// Over `x`, every byte of it is read before it is written over: at the same positions each
1568/// limb or block is read before it is written; for a result further on in memory, the head
1569/// first and the rest from the least significant byte up; for one further back, the head is
1570/// held back (or `x` moved first, for a long head), the tail first and the rest from the most
1571/// significant byte down.
1572///
1573/// # Safety
1574///
1575/// The magnitudes' significant bytes must be valid for reads, `dst` for writing the `len` bytes,
1576/// and `place` true of them; the plan must be that of `x` and `y`.
1577#[inline(never)]
1578unsafe fn compute<const XBE: bool, const YBE: bool>(
1579 dst: *mut u8,
1580 x: *const u8,
1581 y: *const u8,
1582 plan: &Plan,
1583 place: Place,
1584) {
1585 let mixed = XBE != YBE;
1586 let len = plan.len;
1587 let short = plan.lx.min(plan.ly);
1588 let lo = 8 * plan.head;
1589 // The head's limbs below the end of the result, the bulk `lo..bulk` and the tail `rest..len`.
1590 let held = plan.head.min(len.div_ceil(8));
1591 let bulk = short.min(len);
1592 let rest = short.max(lo);
1593 // SAFETY: as the caller guarantees; every position written is below `len`, and every one
1594 // read is significant in its magnitude. The order of the steps is that of the doc comment.
1595 unsafe {
1596 match place {
1597 Place::Below if held > HELD => {
1598 // Moves the bytes of `x` the result needs to its positions first: those below
1599 // the result's end, which is all that the result depends on.
1600 let m = plan.lx.min(len);
1601 ptr::copy(x.sub(m), dst.sub(m), m);
1602 let moved = Plan { lx: m, ..*plan };
1603 compute::<XBE, YBE>(dst, dst, y, &moved, Place::Same);
1604 }
1605 Place::Below => {
1606 let mut limbs = [0u64; HELD];
1607 let mut flags = Flags {
1608 x: plan.nx,
1609 y: plan.ny,
1610 carry: plan.negative,
1611 };
1612 for (i, w) in limbs.iter_mut().enumerate().take(held) {
1613 *w = flags.next(
1614 plan.g,
1615 limb::<XBE>(x, plan.lx, i),
1616 limb::<YBE>(y, plan.ly, i),
1617 );
1618 }
1619 tail::<XBE, YBE>(dst, x, y, plan, rest, place);
1620 if bulk > lo {
1621 let n = bulk - lo;
1622 logic::<false>(
1623 plan.g,
1624 mixed,
1625 at_mut::<XBE>(dst, lo, n),
1626 at::<XBE>(x, lo, n),
1627 at::<YBE>(y, lo, n),
1628 n,
1629 );
1630 }
1631 for (i, &w) in limbs.iter().enumerate().take(held) {
1632 put_limb::<XBE>(dst, len, i, w);
1633 }
1634 }
1635 _ => {
1636 let mut flags = Flags {
1637 x: plan.nx,
1638 y: plan.ny,
1639 carry: plan.negative,
1640 };
1641 for i in 0..held {
1642 let w = flags.next(
1643 plan.g,
1644 limb::<XBE>(x, plan.lx, i),
1645 limb::<YBE>(y, plan.ly, i),
1646 );
1647 put_limb::<XBE>(dst, len, i, w);
1648 }
1649 if bulk > lo {
1650 let n = bulk - lo;
1651 let (d, xs, ys) = (
1652 at_mut::<XBE>(dst, lo, n),
1653 at::<XBE>(x, lo, n),
1654 at::<YBE>(y, lo, n),
1655 );
1656 if place == Place::Above {
1657 logic::<true>(plan.g, mixed, d, xs, ys, n);
1658 } else {
1659 logic::<false>(plan.g, mixed, d, xs, ys, n);
1660 }
1661 }
1662 tail::<XBE, YBE>(dst, x, y, plan, rest, place);
1663 }
1664 }
1665 }
1666}
1667
1668/// Writes the tail of the result, positions `rest..len`, from the longer magnitude, unless they
1669/// are already there; or the zero byte of a zero result that nothing else writes.
1670///
1671/// # Safety
1672///
1673/// As for [`compute`].
1674#[inline(always)]
1675unsafe fn tail<const XBE: bool, const YBE: bool>(
1676 dst: *mut u8,
1677 x: *const u8,
1678 y: *const u8,
1679 plan: &Plan,
1680 rest: usize,
1681 place: Place,
1682) {
1683 let len = plan.len;
1684 if len <= rest {
1685 return;
1686 }
1687 let n = len - rest;
1688 // SAFETY: as the caller guarantees: positions `rest..len` are significant in the longer
1689 // magnitude, and below `len` in the result.
1690 unsafe {
1691 match plan.tail {
1692 Tail::X if place != Place::Same => {
1693 ptr::copy(at::<XBE>(x, rest, n), at_mut::<XBE>(dst, rest, n), n);
1694 }
1695 Tail::Y if XBE != YBE => {
1696 kernels::copy_reversed(at_mut::<XBE>(dst, rest, n), at::<YBE>(y, rest, n), n);
1697 }
1698 Tail::Y => {
1699 ptr::copy_nonoverlapping(at::<YBE>(y, rest, n), at_mut::<XBE>(dst, rest, n), n);
1700 }
1701 Tail::Zero => {
1702 // Zero, from operands of which one is zero and neither is negative: its byte is
1703 // all that the head and the bulk leave out.
1704 ptr::write_bytes(at_mut::<XBE>(dst, rest, n), 0, n);
1705 }
1706 Tail::X => {}
1707 }
1708 }
1709}
1710
1711/// A kernel: `dst[k] = g(x[k], y[k])` over `n` bytes.
1712type Kernel = unsafe fn(*mut u8, *const u8, *const u8, usize);
1713
1714/// The kernels by direction, `y` reversed or not, and the operation `g`.
1715const KERNELS: [[[Kernel; 5]; 2]; 2] = [
1716 [
1717 [
1718 kernels::logic::<AND, false, false>,
1719 kernels::logic::<OR, false, false>,
1720 kernels::logic::<XOR, false, false>,
1721 kernels::logic::<AND_NOT, false, false>,
1722 kernels::logic::<NOT_AND, false, false>,
1723 ],
1724 [
1725 kernels::logic::<AND, true, false>,
1726 kernels::logic::<OR, true, false>,
1727 kernels::logic::<XOR, true, false>,
1728 kernels::logic::<AND_NOT, true, false>,
1729 kernels::logic::<NOT_AND, true, false>,
1730 ],
1731 ],
1732 [
1733 [
1734 kernels::logic::<AND, false, true>,
1735 kernels::logic::<OR, false, true>,
1736 kernels::logic::<XOR, false, true>,
1737 kernels::logic::<AND_NOT, false, true>,
1738 kernels::logic::<NOT_AND, false, true>,
1739 ],
1740 [
1741 kernels::logic::<AND, true, true>,
1742 kernels::logic::<OR, true, true>,
1743 kernels::logic::<XOR, true, true>,
1744 kernels::logic::<AND_NOT, true, true>,
1745 kernels::logic::<NOT_AND, true, true>,
1746 ],
1747 ],
1748];
1749
1750/// Runs the kernel of the operation `g` over the `n` bytes at `dst`, `x` and `y`, in the order
1751/// of memory, `y` reversed when `mixed`; from the top down when `DOWN`. One call through a table,
1752/// whose target is the same from one call to the next for the same operation and signs.
1753///
1754/// # Safety
1755///
1756/// As for the kernels.
1757#[inline(always)]
1758unsafe fn logic<const DOWN: bool>(
1759 g: u8,
1760 mixed: bool,
1761 dst: *mut u8,
1762 x: *const u8,
1763 y: *const u8,
1764 n: usize,
1765) {
1766 // SAFETY: as the caller guarantees; `g` is one of the five operations.
1767 unsafe { KERNELS[usize::from(DOWN)][usize::from(mixed)][usize::from(g)](dst, x, y, n) }
1768}
1769
1770// Not
1771
1772/// `!a` for a borrowed `a`, in one new vector: `-(A + 1)` for `a >= 0`, `A - 1` for `a < 0`.
1773#[inline(never)]
1774fn not_new(a: &Number) -> Number {
1775 let order = a.byte_order;
1776 if a.value.len() <= SMALL {
1777 // SAFETY: the vector holds at most 16 bytes.
1778 let s = unsafe { small_not(a) };
1779 return small_number(order, s);
1780 }
1781 let (value, negative) = if order == ByteOrder::BigEndian {
1782 not_copy::<true>(a)
1783 } else {
1784 not_copy::<false>(a)
1785 };
1786 Number {
1787 value,
1788 negative,
1789 byte_order: order,
1790 }
1791}
1792
1793/// `!a` for a small `a`, in registers.
1794///
1795/// # Safety
1796///
1797/// The vector of `a` must hold at most [`SMALL`] bytes.
1798#[inline(always)]
1799unsafe fn small_not(a: &Number) -> Small {
1800 // SAFETY: as the caller guarantees.
1801 let x = unsafe { read_small(&a.value, a.byte_order) };
1802 if a.negative && x != 0 {
1803 small_of(x - 1, false, false)
1804 } else {
1805 let (m, carry) = x.overflowing_add(1);
1806 small_of(m, carry, true)
1807 }
1808}
1809
1810/// `!a` in a new vector, for `a` in the layout `BE`: its bytes and its sign.
1811///
1812/// For a magnitude of more than eight bytes whose eight least significant ones the `+ 1` (or the
1813/// `- 1`) does not carry (or borrow) out of, as for random numbers, the magnitude is copied and
1814/// those eight bytes written with the one added (or taken); otherwise as [`step`] writes it.
1815fn not_copy<const BE: bool>(a: &Number) -> (Vec<u8>, bool) {
1816 let l = sig_len::<BE>(&a.value);
1817 let src = end::<BE>(&a.value);
1818 let negative = !(a.negative && l > 0);
1819 if l > 8 {
1820 // SAFETY: the eight least significant bytes are significant.
1821 let w = unsafe { load::<BE>(src, 0) };
1822 let (low, out) = if negative {
1823 w.overflowing_add(1)
1824 } else {
1825 w.overflowing_sub(1)
1826 };
1827 if !out {
1828 let mut v = Vec::<u8>::with_capacity(l);
1829 // SAFETY: the new vector has room for the `l` bytes of the result, the magnitude's with
1830 // the eight least significant ones replaced, all of which are written before the
1831 // length is set.
1832 unsafe {
1833 let base = v.as_mut_ptr();
1834 ptr::copy_nonoverlapping(at::<BE>(src, 0, l), base, l);
1835 store::<BE>(if BE { base.add(l) } else { base }, 0, low);
1836 v.set_len(l);
1837 }
1838 return (v, negative);
1839 }
1840 }
1841 // SAFETY: `run` reads the significant bytes only.
1842 let (r, len) = unsafe { run::<BE>(src, l, negative) };
1843 let mut v = Vec::<u8>::with_capacity(len);
1844 let base = v.as_mut_ptr();
1845 let dst = if BE {
1846 // SAFETY: the end of the new vector's `len` bytes.
1847 unsafe { base.add(len) }
1848 } else {
1849 base
1850 };
1851 // SAFETY: the new vector has room for the `len` bytes, all of which `step` writes.
1852 unsafe {
1853 step::<BE>(dst, src, l, r, len, negative, false);
1854 v.set_len(len);
1855 }
1856 (v, negative)
1857}
1858
1859/// `!a` in the vector of `a`.
1860#[inline(never)]
1861fn not_in_place(a: &mut Number) {
1862 if a.value.len() <= SMALL {
1863 // SAFETY: the vector holds at most 16 bytes.
1864 let s = unsafe { small_not(a) };
1865 put_small(&mut a.value, a.byte_order, s);
1866 a.negative = s.negative;
1867 return;
1868 }
1869 if a.byte_order == ByteOrder::BigEndian {
1870 not_in::<true>(a);
1871 } else {
1872 not_in::<false>(a);
1873 }
1874}
1875
1876/// [`not_in_place`] for `a` in the layout `BE`.
1877///
1878/// A magnitude of more than eight bytes whose eight least significant ones the `+ 1` (or the
1879/// `- 1`) does not carry (or borrow) out of, as for random numbers, keeps its length, and only
1880/// those eight bytes are written, in place (big-endian, when no zero byte comes before the
1881/// magnitude). Measured on an Apple M4 Max, `!a` took 15 to 16 cycles so, from 17 bytes to
1882/// 64 KiB, against 18 to 19 with the run and the step of the general case; most of it is the
1883/// moving of `a` in and out, as num-bigint's `!a` takes as long, and GMP's `mpz_com(a, a)`, in
1884/// place, 7.
1885fn not_in<const BE: bool>(a: &mut Number) {
1886 let n = a.value.len();
1887 let l = sig_len::<BE>(&a.value);
1888 let negative = !(a.negative && l > 0);
1889 if l > 8 && (!BE || l == n) {
1890 let base = a.value.as_mut_ptr();
1891 let e = if BE {
1892 // SAFETY: the end of the vector, `l == n` bytes on.
1893 unsafe { base.add(n) }
1894 } else {
1895 base
1896 };
1897 // SAFETY: the eight least significant bytes are significant.
1898 let w = unsafe { load::<BE>(e, 0) };
1899 let (low, out) = if negative {
1900 w.overflowing_add(1)
1901 } else {
1902 w.overflowing_sub(1)
1903 };
1904 if !out {
1905 // SAFETY: the same eight bytes, and `l <= n` bytes stay.
1906 unsafe {
1907 store::<BE>(e, 0, low);
1908 a.value.set_len(l);
1909 }
1910 a.negative = negative;
1911 return;
1912 }
1913 }
1914 // SAFETY: `run` reads the significant bytes only.
1915 let (r, len) = unsafe { run::<BE>(end::<BE>(&a.value), l, negative) };
1916 if a.value.capacity() < len {
1917 // Only `0xFF…FF + 1`, one byte longer, which is all zeros but its top byte.
1918 let (value, negative) = not_copy::<BE>(a);
1919 a.value = value;
1920 a.negative = negative;
1921 return;
1922 }
1923 a.negative = negative;
1924 let base = a.value.as_mut_ptr();
1925 // SAFETY: the vector has room for the `len` bytes of the result, all of which `step` writes.
1926 // Big-endian, a result whose length differs from `l` has all its bytes written, as `step`
1927 // says, so the bytes of `a` need not move; one of the same length as `l` is written over
1928 // them, moved to the start of the vector first when zero bytes come before them.
1929 unsafe {
1930 if BE {
1931 if len == l && n > l {
1932 ptr::copy(base.add(n - l), base, l);
1933 }
1934 let in_place = len == l;
1935 step::<true>(
1936 base.add(len),
1937 base.add(l).cast_const(),
1938 l,
1939 r,
1940 len,
1941 negative,
1942 in_place,
1943 );
1944 } else {
1945 step::<false>(base, base.cast_const(), l, r, len, negative, true);
1946 }
1947 a.value.set_len(len);
1948 }
1949}
1950
1951/// For `!a` with a magnitude of `l` significant bytes at the least significant end `src` in the
1952/// layout `BE`: the position `r` of the lowest byte that the `+ 1` (when `plus`, for a result
1953/// that is negative) or the `- 1` changes, the bytes below it being `0xFF` or zero, and the
1954/// length of the result.
1955///
1956/// # Safety
1957///
1958/// The `l` bytes must be valid for reads.
1959#[inline(always)]
1960unsafe fn run<const BE: bool>(src: *const u8, l: usize, plus: bool) -> (usize, usize) {
1961 // The bytes the run passes through: `0xFF` for `+ 1`, zero for `- 1`.
1962 let pass = if plus { u64::MAX } else { 0 };
1963 let mut r = 0;
1964 // SAFETY: every read is of positions below `l`.
1965 unsafe {
1966 while r + 8 <= l && load::<BE>(src, r) == pass {
1967 r += 8;
1968 }
1969 while r < l && get::<BE>(src, r) == pass as u8 {
1970 r += 1;
1971 }
1972 let len = if plus {
1973 // `0xFF…FF + 1` is one byte longer, and `0 + 1` is 1.
1974 if r == l { l + 1 } else { l }
1975 } else if r + 1 == l && get::<BE>(src, r) == 1 {
1976 // `0x01_00…00 - 1` is one byte shorter, and `1 - 1` is zero, one byte.
1977 (l - 1).max(1)
1978 } else {
1979 l
1980 };
1981 (r, len)
1982 }
1983}
1984
1985/// Writes the `len` bytes of `A + 1` (when `plus`) or `A - 1` at the least significant end `dst`
1986/// in the layout `BE`, for `A` of `l` significant bytes at `src` whose run of `0xFF` (or zero)
1987/// bytes ends at `r`: those bytes turn to zero (or `0xFF`), byte `r` gains (or loses) one, and the
1988/// others are copied, unless `in_place`, where they are already there. A result of another
1989/// length than `l` is all zeros but a top byte of 1, or all `0xFF`, and reads nothing.
1990///
1991/// # Safety
1992///
1993/// `r` and `len` must be those [`run`] gives. The `l` bytes at `src` must be valid for reads and
1994/// the `len` bytes at `dst` for writes; `in_place` only when `dst` is `src`, or `len != l`.
1995#[inline(always)]
1996unsafe fn step<const BE: bool>(
1997 dst: *mut u8,
1998 src: *const u8,
1999 l: usize,
2000 r: usize,
2001 len: usize,
2002 plus: bool,
2003 in_place: bool,
2004) {
2005 let fill = if plus { 0 } else { 0xFF };
2006 // SAFETY: as the caller guarantees; every write is of positions below `len`, every read of
2007 // positions below `l`.
2008 unsafe {
2009 if len != l {
2010 // `0xFF…FF + 1` (or `0 + 1`), all zeros but a top byte of 1, or `0x01_00…00 - 1`,
2011 // all `0xFF`.
2012 ptr::write_bytes(at_mut::<BE>(dst, 0, len), fill, len);
2013 if plus {
2014 set::<BE>(dst, len - 1, 1);
2015 }
2016 return;
2017 }
2018 // Of the same length, the run ends inside the magnitude.
2019 ptr::write_bytes(at_mut::<BE>(dst, 0, r), fill, r);
2020 let byte = get::<BE>(src, r);
2021 set::<BE>(dst, r, if plus { byte + 1 } else { byte - 1 });
2022 if !in_place && l > r + 1 {
2023 let n = l - r - 1;
2024 ptr::copy_nonoverlapping(at::<BE>(src, r + 1, n), at_mut::<BE>(dst, r + 1, n), n);
2025 }
2026 }
2027}
2028
2029// The bits of a number
2030
2031impl Number {
2032 /// Returns the number of bits of the magnitude, `|self|.ilog2() + 1`, or 0 for zero: the
2033 /// position of the highest one plus one, as `BigInt::bits` in num-bigint and
2034 /// `mpz_sizeinbase(x, 2)` in GMP (which gives 1 for zero).
2035 ///
2036 /// It takes constant time for a number in the shortest form: the length of the magnitude and
2037 /// its top byte decide.
2038 ///
2039 /// # Examples
2040 ///
2041 /// ```
2042 /// use a::math::numbers::{ByteOrder, Number};
2043 ///
2044 /// assert_eq!(Number::new_from_i32(-0x1FF, ByteOrder::BigEndian).bits(), 9);
2045 /// assert_eq!(Number::new_from_u64(1 << 40, ByteOrder::LittleEndian).bits(), 41);
2046 /// assert_eq!(Number::new_from_u8(0, ByteOrder::BigEndian).bits(), 0);
2047 /// ```
2048 pub fn bits(&self) -> u64 {
2049 let (l, top) = if self.byte_order == ByteOrder::BigEndian {
2050 top_byte::<true>(&self.value)
2051 } else {
2052 top_byte::<false>(&self.value)
2053 };
2054 if l == 0 {
2055 0
2056 } else {
2057 8 * (l as u64 - 1) + u64::from(8 - top.leading_zeros())
2058 }
2059 }
2060
2061 /// Returns the number of ones in the magnitude, as Python's `int.bit_count` and num-bigint's
2062 /// `BigUint::count_ones` count them, and GMP's `mpz_popcount` for numbers that are not
2063 /// negative: the sign is not counted. (In two's complement a negative number has infinitely
2064 /// many ones, which `mpz_popcount` gives as its largest value.)
2065 ///
2066 /// The bytes are counted as they are stored, in either byte order, sixteen at a time with
2067 /// NEON's `cnt` on aarch64.
2068 ///
2069 /// # Examples
2070 ///
2071 /// ```
2072 /// use a::math::numbers::{ByteOrder, Number};
2073 ///
2074 /// assert_eq!(Number::new_from_i32(0b1011, ByteOrder::BigEndian).count_ones(), 3);
2075 /// // The magnitude of -0b1011 has as many.
2076 /// assert_eq!(Number::new_from_i32(-0b1011, ByteOrder::LittleEndian).count_ones(), 3);
2077 /// ```
2078 pub fn count_ones(&self) -> u64 {
2079 let v = &self.value;
2080 if v.len() <= SMALL {
2081 // As the addition reads a short magnitude, inline; the order of the bytes does not
2082 // matter.
2083 // SAFETY: the vector holds at most 16 bytes.
2084 return u64::from(unsafe { read_small(v, ByteOrder::LittleEndian) }.count_ones());
2085 }
2086 // SAFETY: the bytes of the vector are valid for reads.
2087 unsafe { kernels::count_ones(v.as_ptr(), v.len()) }
2088 }
2089
2090 /// Returns the number of zeros below the lowest one of the magnitude, the position of that
2091 /// one, or `None` for zero, as num-bigint's `BigInt::trailing_zeros` and GMP's `mpz_scan1(x, 0)`
2092 /// give it. The same for `x` and `-x`: in two's complement, `-x` has its lowest one where
2093 /// `x` has.
2094 ///
2095 /// The bytes are read from the least significant up, eight at a time while they are zero, so
2096 /// for random numbers the first read decides.
2097 ///
2098 /// # Examples
2099 ///
2100 /// ```
2101 /// use a::math::numbers::{ByteOrder, Number};
2102 ///
2103 /// assert_eq!(Number::new_from_i32(-0x500, ByteOrder::BigEndian).trailing_zeros(), Some(8));
2104 /// assert_eq!(Number::new_from_u8(0, ByteOrder::LittleEndian).trailing_zeros(), None);
2105 /// ```
2106 pub fn trailing_zeros(&self) -> Option<u64> {
2107 // SAFETY: `lowest` reads the bytes of the vector only.
2108 unsafe {
2109 if self.byte_order == ByteOrder::BigEndian {
2110 lowest::<true>(&self.value)
2111 } else {
2112 lowest::<false>(&self.value)
2113 }
2114 }
2115 }
2116
2117 /// Returns bit `i` of the number in infinite two's complement, as num-bigint's `BigInt::bit`
2118 /// and GMP's `mpz_tstbit`: for a negative number, `-x` is `!x + 1`, so its bits are those of
2119 /// `!(|x| - 1)`, and all those above the magnitude are ones.
2120 ///
2121 /// For a number that is not negative this takes constant time; for a negative one, the bytes
2122 /// below bit `i` are read from the nearest down until one is not zero, which for random
2123 /// numbers is the first.
2124 ///
2125 /// # Examples
2126 ///
2127 /// ```
2128 /// use a::math::numbers::{ByteOrder, Number};
2129 ///
2130 /// // -4 is …11111100.
2131 /// let n = Number::new_from_i32(-4, ByteOrder::BigEndian);
2132 /// assert!(!n.bit(0) && !n.bit(1) && n.bit(2) && n.bit(3) && n.bit(1000));
2133 /// let n = Number::new_from_i32(4, ByteOrder::LittleEndian);
2134 /// assert!(n.bit(2) && !n.bit(3) && !n.bit(1000));
2135 /// ```
2136 pub fn bit(&self, i: u64) -> bool {
2137 if self.byte_order == ByteOrder::BigEndian {
2138 bit_of::<true>(self, i)
2139 } else {
2140 bit_of::<false>(self, i)
2141 }
2142 }
2143
2144 /// Sets bit `i` of the number in infinite two's complement to `value`, as num-bigint's
2145 /// `BigInt::set_bit` and GMP's `mpz_setbit` and `mpz_clrbit` do, and stores the result back
2146 /// as a sign and a magnitude, in the byte order of `self`, in the shortest form.
2147 ///
2148 /// For a number that is not negative, the bit of the magnitude is set or cleared. For a
2149 /// negative one, whose magnitude `X` has its lowest one at position `t`: above `t` the bits are
2150 /// those of `!X`, so setting bit `i > t` clears it in `X` and clearing it sets it; bit `t` is
2151 /// one, and clearing it adds `2^t` to `X`; below `t` the bits are zeros, and setting bit `i`
2152 /// subtracts `2^i` from `X`.
2153 ///
2154 /// The vector grows as needed, by `Vec`'s rules, and shrinks to the shortest form; a
2155 /// big-endian magnitude that grows or shrinks at its top moves its bytes, as its most
2156 /// significant byte comes first. Otherwise a number in the shortest form costs constant time
2157 /// (but for the borrows and carries of a negative number, which for random numbers end in the
2158 /// first byte).
2159 ///
2160 /// # Panics
2161 ///
2162 /// When the result is too long to be allocated.
2163 ///
2164 /// # Examples
2165 ///
2166 /// ```
2167 /// use a::math::numbers::{ByteOrder, Number};
2168 ///
2169 /// let mut n = Number::new_from_i32(5, ByteOrder::BigEndian);
2170 /// n.set_bit(9, true);
2171 /// assert_eq!(n.value, [0x02, 0x05]);
2172 ///
2173 /// // -4 is …11111100: setting bit 0 gives …11111101, -3.
2174 /// let mut n = Number::new_from_i32(-4, ByteOrder::LittleEndian);
2175 /// n.set_bit(0, true);
2176 /// assert_eq!(n.value, [3]);
2177 /// assert!(n.is_negative());
2178 /// // Clearing bit 2 gives …11111001, -7.
2179 /// n.set_bit(2, false);
2180 /// assert_eq!(n.value, [7]);
2181 /// assert!(n.is_negative());
2182 /// ```
2183 #[track_caller]
2184 pub fn set_bit(&mut self, i: u64, value: bool) {
2185 if self.byte_order == ByteOrder::BigEndian {
2186 set_bit_in::<true>(self, i, value);
2187 } else {
2188 set_bit_in::<false>(self, i, value);
2189 }
2190 }
2191}
2192
2193/// The significant length of the magnitude in `v` in the layout `BE`, and its top byte (0 for
2194/// zero).
2195#[inline(always)]
2196fn top_byte<const BE: bool>(v: &[u8]) -> (usize, u8) {
2197 let l = significant_len::<BE>(v);
2198 if l == 0 {
2199 return (0, 0);
2200 }
2201 // SAFETY: position `l - 1` is in the vector.
2202 (l, unsafe { get::<BE>(end::<BE>(v), l - 1) })
2203}
2204
2205/// The position of the lowest one of the magnitude in `v` in the layout `BE`, or `None` for
2206/// zero.
2207///
2208/// # Safety
2209///
2210/// None beyond the validity of `v`; unsafe for the raw reads inside.
2211#[inline(always)]
2212unsafe fn lowest<const BE: bool>(v: &[u8]) -> Option<u64> {
2213 let (e, n) = (end::<BE>(v), v.len());
2214 let mut p = 0;
2215 // SAFETY: every read is of positions below `n`.
2216 unsafe {
2217 while p + 8 <= n {
2218 let w = load::<BE>(e, p);
2219 if w != 0 {
2220 return Some(8 * p as u64 + u64::from(w.trailing_zeros()));
2221 }
2222 p += 8;
2223 }
2224 while p < n {
2225 let b = get::<BE>(e, p);
2226 if b != 0 {
2227 return Some(8 * p as u64 + u64::from(b.trailing_zeros()));
2228 }
2229 p += 1;
2230 }
2231 }
2232 None
2233}
2234
2235/// Whether any of the positions `0..q` of the magnitude at the least significant end `e` in the
2236/// layout `BE` is not zero: from `q - 1` down, eight at a time.
2237///
2238/// # Safety
2239///
2240/// The `q` positions must be valid for reads.
2241#[inline(always)]
2242unsafe fn any_below<const BE: bool>(e: *const u8, q: usize) -> bool {
2243 let mut p = q;
2244 // SAFETY: every read is of positions below `q`.
2245 unsafe {
2246 while p >= 8 {
2247 if load::<BE>(e, p - 8) != 0 {
2248 return true;
2249 }
2250 p -= 8;
2251 }
2252 while p > 0 {
2253 if get::<BE>(e, p - 1) != 0 {
2254 return true;
2255 }
2256 p -= 1;
2257 }
2258 }
2259 false
2260}
2261
2262/// Bit `k` of position `q` of the magnitude at the least significant end `e` in the layout `BE`,
2263/// and whether any bit below it is set: one read of the eight positions that end with `q`, whose
2264/// test a random number passes every time, and only when they are all zero below that bit are
2265/// the positions further down read. (A test of the bits of the byte at `q` alone would be a coin
2266/// toss for a random `k`.) Measured on an Apple M4 Max, `set_bit` of negative numbers of 1 KiB
2267/// at random positions took 8 to 10 cycles so, in either byte order, against 8 and 19 with a
2268/// read of the byte and then of the eight below it, and GMP's `mpz_setbit` 7.
2269///
2270/// # Safety
2271///
2272/// Positions `0..=q` must be valid for reads.
2273#[inline(always)]
2274unsafe fn bit_and_below<const BE: bool>(e: *const u8, q: usize, k: u32) -> (bool, bool) {
2275 // SAFETY: as the caller guarantees; below position 7, `limb` reads the `q + 1` positions.
2276 unsafe {
2277 let (word, s) = if q >= 7 {
2278 (load::<BE>(e, q - 7), 56 + k)
2279 } else {
2280 (limb::<BE>(e, q + 1, 0), 8 * q as u32 + k)
2281 };
2282 let own = (word >> s) & 1 == 1;
2283 let below = word & ((1 << s) - 1) != 0 || (q > 7 && any_below::<BE>(e, q - 7));
2284 (own, below)
2285 }
2286}
2287
2288/// [`Number::bit`] for a number in the layout `BE`.
2289#[inline(always)]
2290fn bit_of<const BE: bool>(a: &Number, i: u64) -> bool {
2291 let (e, n) = (end::<BE>(&a.value), a.value.len());
2292 let (q, k) = (i / 8, (i % 8) as u32);
2293 if q >= n as u64 {
2294 // Above the magnitude: ones for a negative number, which zero is not.
2295 return a.negative && significant_len::<BE>(&a.value) > 0;
2296 }
2297 let q = q as usize;
2298 // SAFETY: position `q` is below `n`.
2299 unsafe {
2300 if !a.negative {
2301 return (get::<BE>(e, q) >> k) & 1 == 1;
2302 }
2303 // Bit `i` of `-x` is that of `x` up to its lowest one, and the opposite above it.
2304 let (own, below) = bit_and_below::<BE>(e, q, k);
2305 own ^ below
2306 }
2307}
2308
2309/// [`Number::set_bit`] for a number in the layout `BE`.
2310#[track_caller]
2311fn set_bit_in<const BE: bool>(a: &mut Number, i: u64, value: bool) {
2312 let l = sig_len::<BE>(&a.value);
2313 if l != a.value.len() || l == 0 {
2314 // The shortest form first: the bytes above the magnitude go, and a zero is not negative.
2315 trim::<BE>(&mut a.value, l);
2316 if l == 0 {
2317 a.negative = false;
2318 }
2319 }
2320 if !a.negative {
2321 if value {
2322 set_magnitude_bit::<BE>(&mut a.value, i);
2323 } else {
2324 clear_magnitude_bit::<BE>(&mut a.value, i);
2325 }
2326 return;
2327 }
2328 // A negative number's bit `i` is that of `!(x - 1)`: the opposite of its magnitude's above
2329 // the lowest one, which is at `i` when no bit below is set and bit `i` is.
2330 let (e, n) = (end::<BE>(&a.value), a.value.len());
2331 let (q, k) = (i / 8, (i % 8) as u32);
2332 let (below, own) = if q >= n as u64 {
2333 (true, false)
2334 } else {
2335 // SAFETY: position `q` is below `n`.
2336 let (own, below) = unsafe { bit_and_below::<BE>(e, q as usize, k) };
2337 (below, own)
2338 };
2339 match (below, own, value) {
2340 // Above the lowest one, the bits are those of `!x`.
2341 (true, _, true) => clear_magnitude_bit::<BE>(&mut a.value, i),
2342 (true, _, false) => set_magnitude_bit::<BE>(&mut a.value, i),
2343 // The lowest one, cleared: `-x - 2^i`, a magnitude `x + 2^i`.
2344 (false, true, false) => add_power::<BE>(&mut a.value, i),
2345 // Below it, set: `-x + 2^i`, a magnitude `x - 2^i`.
2346 (false, false, true) => subtract_power::<BE>(&mut a.value, i),
2347 _ => {}
2348 }
2349}
2350
2351/// Drops the bytes of `v` above its significant length `l`, keeping one byte for zero.
2352fn trim<const BE: bool>(v: &mut Vec<u8>, l: usize) {
2353 let keep = l.max(1);
2354 if v.len() > keep {
2355 if BE {
2356 v.drain(..v.len() - keep);
2357 } else {
2358 v.truncate(keep);
2359 }
2360 } else if v.is_empty() {
2361 v.push(0);
2362 }
2363}
2364
2365/// Grows the magnitude in `v`, in the shortest form, with zero bytes above it to `len` bytes:
2366/// big-endian, its bytes move up to make room for them at the start.
2367///
2368/// # Panics
2369///
2370/// When it cannot be allocated.
2371#[track_caller]
2372fn grow<const BE: bool>(v: &mut Vec<u8>, len: usize) {
2373 let (n, more) = (v.len(), len - v.len());
2374 if v.try_reserve(more).is_err() {
2375 too_long(len);
2376 }
2377 // SAFETY: the vector has room for `len` bytes; big-endian its `n` bytes move up by `more`,
2378 // and the `more` bytes before them, all of the new ones, are set to zero before the length is.
2379 unsafe {
2380 let p = v.as_mut_ptr();
2381 if BE {
2382 ptr::copy(p, p.add(more), n);
2383 ptr::write_bytes(p, 0, more);
2384 } else {
2385 ptr::write_bytes(p.add(n), 0, more);
2386 }
2387 v.set_len(len);
2388 }
2389}
2390
2391/// Panics for a `set_bit` whose result cannot be allocated.
2392#[cold]
2393#[inline(never)]
2394#[track_caller]
2395fn too_long(len: usize) -> ! {
2396 panic!("a number of {len} bytes cannot be allocated")
2397}
2398
2399/// Panics for a `set_bit` at a position beyond any vector.
2400#[cold]
2401#[inline(never)]
2402#[track_caller]
2403fn too_far(i: u64) -> ! {
2404 panic!("a number with bit {i} set cannot be allocated")
2405}
2406
2407/// Sets bit `i` of the magnitude in `v`, in the shortest form, growing it as needed.
2408#[track_caller]
2409fn set_magnitude_bit<const BE: bool>(v: &mut Vec<u8>, i: u64) {
2410 let n = v.len();
2411 let q = i / 8;
2412 if q >= n as u64 {
2413 let Some(len) = usize::try_from(q).ok().and_then(|q| q.checked_add(1)) else {
2414 too_far(i)
2415 };
2416 grow::<BE>(v, len);
2417 }
2418 let n = v.len();
2419 // SAFETY: position `q` is in the vector.
2420 unsafe {
2421 let e = v.as_mut_ptr().add(if BE { n } else { 0 });
2422 let q = q as usize;
2423 set::<BE>(e, q, get::<BE>(e, q) | (1 << (i % 8)));
2424 }
2425}
2426
2427/// Clears bit `i` of the magnitude in `v`, in the shortest form, shrinking it to the shortest
2428/// form.
2429fn clear_magnitude_bit<const BE: bool>(v: &mut Vec<u8>, i: u64) {
2430 let n = v.len();
2431 let q = i / 8;
2432 if q >= n as u64 {
2433 return;
2434 }
2435 let q = q as usize;
2436 // SAFETY: position `q` is in the vector.
2437 let byte = unsafe {
2438 let e = v.as_mut_ptr().add(if BE { n } else { 0 });
2439 let byte = get::<BE>(e, q) & !(1 << (i % 8));
2440 set::<BE>(e, q, byte);
2441 byte
2442 };
2443 if byte == 0 && q + 1 == n {
2444 let l = significant_len::<BE>(v);
2445 trim::<BE>(v, l);
2446 }
2447}
2448
2449/// Adds `2^t` to the magnitude in `v`, in the shortest form, whose bit `t` is set: the carry runs
2450/// through the bytes above that are `0xFF`, and past the top makes it one byte longer.
2451#[track_caller]
2452fn add_power<const BE: bool>(v: &mut Vec<u8>, t: u64) {
2453 let n = v.len();
2454 let mut q = (t / 8) as usize;
2455 // SAFETY: every position read and written is below `n`.
2456 unsafe {
2457 let e = v.as_mut_ptr().add(if BE { n } else { 0 });
2458 let (byte, carry) = get::<BE>(e, q).overflowing_add(1 << (t % 8));
2459 set::<BE>(e, q, byte);
2460 if !carry {
2461 return;
2462 }
2463 q += 1;
2464 while q < n && get::<BE>(e, q) == 0xFF {
2465 set::<BE>(e, q, 0);
2466 q += 1;
2467 }
2468 if q < n {
2469 set::<BE>(e, q, get::<BE>(e, q) + 1);
2470 return;
2471 }
2472 }
2473 grow::<BE>(v, n + 1);
2474 // SAFETY: position `n` is the new top byte.
2475 unsafe {
2476 let e = v.as_mut_ptr().add(if BE { n + 1 } else { 0 });
2477 set::<BE>(e, n, 1);
2478 }
2479}
2480
2481/// Subtracts `2^i` from the magnitude in `v`, in the shortest form, whose bits below `i` are
2482/// zero and which is above `2^i`: the borrow runs through the zero bytes above, and the result is
2483/// left in the shortest form.
2484fn subtract_power<const BE: bool>(v: &mut Vec<u8>, i: u64) {
2485 let n = v.len();
2486 let mut q = (i / 8) as usize;
2487 // SAFETY: every position read and written is below `n`: the magnitude is above `2^i`, so the
2488 // borrow ends inside it.
2489 unsafe {
2490 let e = v.as_mut_ptr().add(if BE { n } else { 0 });
2491 let (byte, borrow) = get::<BE>(e, q).overflowing_sub(1 << (i % 8));
2492 set::<BE>(e, q, byte);
2493 if borrow {
2494 q += 1;
2495 while get::<BE>(e, q) == 0 {
2496 set::<BE>(e, q, 0xFF);
2497 q += 1;
2498 }
2499 set::<BE>(e, q, get::<BE>(e, q) - 1);
2500 }
2501 }
2502 if q + 1 == n {
2503 let l = significant_len::<BE>(v);
2504 trim::<BE>(v, l);
2505 }
2506}
2507
2508// Positions
2509
2510/// The least significant end of the magnitude in `v` in the layout `BE`: the address of its
2511/// first byte little-endian, and the address one past its last byte big-endian.
2512#[inline(always)]
2513fn end<const BE: bool>(v: &[u8]) -> *const u8 {
2514 if BE { v.as_ptr_range().end } else { v.as_ptr() }
2515}
2516
2517/// The lowest address of positions `p..p + n` of the magnitude at the least significant end
2518/// `end` in the layout `BE`: `end + p` little-endian, `end - p - n` big-endian.
2519///
2520/// # Safety
2521///
2522/// The address must lie in the allocation of `end`.
2523#[inline(always)]
2524unsafe fn at<const BE: bool>(end: *const u8, p: usize, n: usize) -> *const u8 {
2525 // SAFETY: as the caller guarantees.
2526 unsafe { if BE { end.sub(p + n) } else { end.add(p) } }
2527}
2528
2529/// [`at`] for writing.
2530///
2531/// # Safety
2532///
2533/// As for [`at`].
2534#[inline(always)]
2535unsafe fn at_mut<const BE: bool>(end: *mut u8, p: usize, n: usize) -> *mut u8 {
2536 // SAFETY: as the caller guarantees.
2537 unsafe { if BE { end.sub(p + n) } else { end.add(p) } }
2538}
2539
2540/// Reads position `p` of the magnitude at the least significant end `end` in the layout `BE`.
2541///
2542/// # Safety
2543///
2544/// The byte must be valid for reading.
2545#[inline(always)]
2546unsafe fn get<const BE: bool>(end: *const u8, p: usize) -> u8 {
2547 // SAFETY: as the caller guarantees.
2548 unsafe { *at::<BE>(end, p, 1) }
2549}
2550
2551/// Writes position `p` of the magnitude at the least significant end `end` in the layout `BE`.
2552///
2553/// # Safety
2554///
2555/// The byte must be valid for writing.
2556#[inline(always)]
2557unsafe fn set<const BE: bool>(end: *mut u8, p: usize, v: u8) {
2558 // SAFETY: as the caller guarantees.
2559 unsafe { *at_mut::<BE>(end, p, 1) = v };
2560}
2561
2562/// Reads positions `p..p + 8` of the magnitude at the least significant end `end` in the layout
2563/// `BE` as a `u64` whose least significant byte is position `p`.
2564///
2565/// # Safety
2566///
2567/// The eight bytes must be valid for reading; they need no alignment.
2568#[inline(always)]
2569unsafe fn load<const BE: bool>(end: *const u8, p: usize) -> u64 {
2570 // SAFETY: as the caller guarantees.
2571 unsafe {
2572 let bytes = read(at::<BE>(end, p, 8));
2573 if BE {
2574 u64::from_be_bytes(bytes)
2575 } else {
2576 u64::from_le_bytes(bytes)
2577 }
2578 }
2579}
2580
2581/// Writes positions `p..p + 8` of the magnitude at the least significant end `end` in the layout
2582/// `BE`, as [`load`] reads them.
2583///
2584/// # Safety
2585///
2586/// The eight bytes must be valid for writing; they need no alignment.
2587#[inline(always)]
2588unsafe fn store<const BE: bool>(end: *mut u8, p: usize, v: u64) {
2589 // SAFETY: as the caller guarantees.
2590 unsafe {
2591 let bytes = if BE { v.to_be_bytes() } else { v.to_le_bytes() };
2592 write(at_mut::<BE>(end, p, 8), bytes);
2593 }
2594}
2595
2596/// Limb `i`, positions `8i..8i + 8`, of the magnitude of `l` significant bytes at the least
2597/// significant end `end` in the layout `BE`, its positions from `l` up zero: a limb inside it as
2598/// it is, the top one from the eight positions that end at `l` (or, below 8, as the addition
2599/// reads a short magnitude), shifted down.
2600///
2601/// # Safety
2602///
2603/// The `l` bytes must be valid for reads.
2604#[inline(always)]
2605unsafe fn limb<const BE: bool>(end: *const u8, l: usize, i: usize) -> u64 {
2606 let p = 8 * i;
2607 // SAFETY: every read is of positions below `l`.
2608 unsafe {
2609 if p + 8 <= l {
2610 load::<BE>(end, p)
2611 } else if p >= l {
2612 0
2613 } else if l >= 8 {
2614 load::<BE>(end, l - 8) >> (8 * (p + 8 - l))
2615 } else {
2616 let order = if BE {
2617 ByteOrder::BigEndian
2618 } else {
2619 ByteOrder::LittleEndian
2620 };
2621 read_small(&*ptr::slice_from_raw_parts(at::<BE>(end, 0, l), l), order) as u64
2622 }
2623 }
2624}
2625
2626/// Writes limb `i` of a result of `len` bytes at the least significant end `end` in the layout
2627/// `BE`: its positions below `len`.
2628///
2629/// # Safety
2630///
2631/// `8 i < len`, and the `len` bytes must be valid for writes.
2632#[inline(always)]
2633unsafe fn put_limb<const BE: bool>(end: *mut u8, len: usize, i: usize, v: u64) {
2634 let p = 8 * i;
2635 // SAFETY: as the caller guarantees; a part of a limb, `n` from 1 to 7 bytes, is written as
2636 // `write_small` writes so short a sum.
2637 unsafe {
2638 if p + 8 <= len {
2639 store::<BE>(end, p, v);
2640 } else {
2641 let n = len - p;
2642 let order = if BE {
2643 ByteOrder::BigEndian
2644 } else {
2645 ByteOrder::LittleEndian
2646 };
2647 write_small(at_mut::<BE>(end, p, n), order, v, 0, n);
2648 }
2649 }
2650}