Use NonNull in merge_sort

This is more clear about the intent of the pointer and avoids problems
if the allocation returns a null pointer.
This commit is contained in:
Lukas Bergdoll 2023-01-21 10:17:06 +01:00
parent e098eb17e1
commit 703ff60d9f

View File

@ -1203,7 +1203,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
// `is_less` panics. When merging two sorted runs, this buffer holds a copy of the shorter run,
// which will always have length at most `len / 2`.
let buf = BufGuard::new(len / 2, elem_alloc_fn, elem_dealloc_fn);
let buf_ptr = buf.buf_ptr;
let buf_ptr = buf.buf_ptr.as_ptr();
let mut runs = RunVec::new(run_alloc_fn, run_dealloc_fn);
@ -1298,7 +1298,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
where
ElemDeallocF: Fn(*mut T, usize),
{
buf_ptr: *mut T,
buf_ptr: ptr::NonNull<T>,
capacity: usize,
elem_dealloc_fn: ElemDeallocF,
}
@ -1315,7 +1315,11 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
where
ElemAllocF: Fn(usize) -> *mut T,
{
Self { buf_ptr: elem_alloc_fn(len), capacity: len, elem_dealloc_fn }
Self {
buf_ptr: ptr::NonNull::new(elem_alloc_fn(len)).unwrap(),
capacity: len,
elem_dealloc_fn,
}
}
}
@ -1324,7 +1328,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
ElemDeallocF: Fn(*mut T, usize),
{
fn drop(&mut self) {
(self.elem_dealloc_fn)(self.buf_ptr, self.capacity);
(self.elem_dealloc_fn)(self.buf_ptr.as_ptr(), self.capacity);
}
}
@ -1333,7 +1337,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
RunAllocF: Fn(usize) -> *mut TimSortRun,
RunDeallocF: Fn(*mut TimSortRun, usize),
{
buf_ptr: *mut TimSortRun,
buf_ptr: ptr::NonNull<TimSortRun>,
capacity: usize,
len: usize,
run_alloc_fn: RunAllocF,
@ -1350,7 +1354,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
const START_RUN_CAPACITY: usize = 16;
Self {
buf_ptr: run_alloc_fn(START_RUN_CAPACITY),
buf_ptr: ptr::NonNull::new(run_alloc_fn(START_RUN_CAPACITY)).unwrap(),
capacity: START_RUN_CAPACITY,
len: 0,
run_alloc_fn,
@ -1361,15 +1365,15 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
fn push(&mut self, val: TimSortRun) {
if self.len == self.capacity {
let old_capacity = self.capacity;
let old_buf_ptr = self.buf_ptr;
let old_buf_ptr = self.buf_ptr.as_ptr();
self.capacity = self.capacity * 2;
self.buf_ptr = (self.run_alloc_fn)(self.capacity);
self.buf_ptr = ptr::NonNull::new((self.run_alloc_fn)(self.capacity)).unwrap();
// SAFETY: buf_ptr new and old were correctly allocated and old_buf_ptr has
// old_capacity valid elements.
unsafe {
ptr::copy_nonoverlapping(old_buf_ptr, self.buf_ptr, old_capacity);
ptr::copy_nonoverlapping(old_buf_ptr, self.buf_ptr.as_ptr(), old_capacity);
}
(self.run_dealloc_fn)(old_buf_ptr, old_capacity);
@ -1377,7 +1381,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
// SAFETY: The invariant was just checked.
unsafe {
self.buf_ptr.add(self.len).write(val);
self.buf_ptr.as_ptr().add(self.len).write(val);
}
self.len += 1;
}
@ -1390,7 +1394,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
// SAFETY: buf_ptr needs to be valid and len invariant upheld.
unsafe {
// the place we are taking from.
let ptr = self.buf_ptr.add(index);
let ptr = self.buf_ptr.as_ptr().add(index);
// Shift everything down to fill in that spot.
ptr::copy(ptr.add(1), ptr, self.len - index - 1);
@ -1400,7 +1404,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
fn as_slice(&self) -> &[TimSortRun] {
// SAFETY: Safe as long as buf_ptr is valid and len invariant was upheld.
unsafe { &*ptr::slice_from_raw_parts(self.buf_ptr, self.len) }
unsafe { &*ptr::slice_from_raw_parts(self.buf_ptr.as_ptr(), self.len) }
}
fn len(&self) -> usize {
@ -1419,7 +1423,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
if index < self.len {
// SAFETY: buf_ptr and len invariant must be upheld.
unsafe {
return &*(self.buf_ptr.add(index));
return &*(self.buf_ptr.as_ptr().add(index));
}
}
@ -1436,7 +1440,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
if index < self.len {
// SAFETY: buf_ptr and len invariant must be upheld.
unsafe {
return &mut *(self.buf_ptr.add(index));
return &mut *(self.buf_ptr.as_ptr().add(index));
}
}
@ -1452,7 +1456,7 @@ pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
fn drop(&mut self) {
// As long as TimSortRun is Copy we don't need to drop them individually but just the
// whole allocation.
(self.run_dealloc_fn)(self.buf_ptr, self.capacity);
(self.run_dealloc_fn)(self.buf_ptr.as_ptr(), self.capacity);
}
}
}