Skip to content

Commit 1158eb2

Browse files
authored
Merge pull request #52 from eduardosm/unsafe-lehmer
lehmer: borrow lhs/rhs to be able to claim them back later
2 parents ae3b576 + 2341ab5 commit 1158eb2

File tree

1 file changed

+14
-26
lines changed

1 file changed

+14
-26
lines changed

integer/src/gcd/lehmer.rs

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use alloc::alloc::Layout;
2-
use core::{mem, ptr, slice};
2+
use core::borrow::BorrowMut as _;
3+
use core::mem;
34
use dashu_base::{ExtendedGcd, Gcd};
45

56
use crate::{
@@ -347,12 +348,12 @@ pub fn gcd_ext_in_place(
347348
rhs: &mut [Word],
348349
memory: &mut Memory,
349350
) -> (usize, usize, Sign) {
350-
let (lhs_len, rhs_len) = (lhs.len(), rhs.len());
351-
let (lhs_ptr, rhs_ptr) = (lhs.as_mut_ptr(), rhs.as_mut_ptr());
351+
let lhs_len = lhs.len();
352352

353353
// keep x >= y though the algorithm, and track the source of x and y using the swapped flag
354354
debug_assert!(cmp_in_place(lhs, rhs).is_ge());
355-
let (mut x, mut y) = (lhs, rhs);
355+
// Use `borrow_mut` to be able to claim back `lhs` and `rhs`
356+
let (mut x, mut y) = (lhs.borrow_mut(), rhs.borrow_mut());
356357
let mut swapped = false;
357358

358359
// the normal way is to have four variables s0, s1, t0, t1 and keep gcd(x, y) = gcd(lhs, rhs),
@@ -449,25 +450,19 @@ pub fn gcd_ext_in_place(
449450
// If y is zero, then the gcd result is in x now.
450451
// Note that y.len() == 0 is equivalent to y == 0, which is guaranteed by trim_leading_zeros.
451452
if y.is_empty() {
452-
// SAFETY: see the comments in the block. The safety here need to be carefully managed.
453-
unsafe {
454-
if !swapped {
455-
// if not swapped, then x is originated from lhs, copy it to rhs
456-
debug_assert!(x.as_ptr() == lhs_ptr);
457-
debug_assert!(x.len() <= rhs_len);
458-
459-
// SAFETY: at this point, x should be from lhs, so it's not overlapping with rhs
460-
ptr::copy_nonoverlapping(x.as_ptr(), rhs_ptr, x.len());
461-
}
462-
// SAFETY: t0 is temporarily allocated space, it won't overlap with lhs or rhs
463-
ptr::copy_nonoverlapping(t0.as_ptr(), lhs_ptr, t0_len);
453+
let x_len = x.len();
454+
// We are not using the borrwed `x` / `y` anymore, so we can
455+
// claim back the original `lhs` / `rhs`.
456+
if !swapped {
457+
rhs[..x_len].copy_from_slice(&lhs[..x_len]);
464458
}
459+
lhs[..t0_len].copy_from_slice(&t0[..t0_len]);
465460
let sign = if swapped {
466461
Sign::Positive
467462
} else {
468463
Sign::Negative
469464
};
470-
return (x.len(), t0_len, sign);
465+
return (x_len, t0_len, sign);
471466
}
472467

473468
// before forwarding to single word gcd, first reduce x by y:
@@ -491,15 +486,8 @@ pub fn gcd_ext_in_place(
491486
// let lhs stores |b| = |cx| * t0 + |cy| * t1
492487
// by now, number of words in |b| should be close to lhs
493488

494-
// SAFETY: we don't hold any reference to lhs and rhs now, so there will be no
495-
// data racing. The pointer and length are from the original slice, so the slice
496-
// will be valid.
497-
let (lhs, rhs) = unsafe {
498-
(
499-
slice::from_raw_parts_mut(lhs_ptr, lhs_len),
500-
slice::from_raw_parts_mut(rhs_ptr, rhs_len),
501-
)
502-
};
489+
// We are not using the borrwed `x` / `y` anymore, so we can
490+
// claim back the original `lhs` / `rhs`.
503491
*rhs.first_mut().unwrap() = g_word;
504492
lhs.fill(0);
505493

0 commit comments

Comments
 (0)