cl_generic_vec/raw/heap/
nightly.rs1use crate::raw::{AllocError, AllocResult, Storage, StorageWithCapacity};
2
3use core::{alloc::Layout, ptr::NonNull};
4use std::{alloc::handle_alloc_error, mem::MaybeUninit};
5
6use std::alloc::Allocator;
7
8enum OnFailure {
9 Abort,
10 Error,
11}
12
13type Heap<T, A> = Box<[MaybeUninit<T>], A>;
14
15pub(crate) unsafe fn box_from_raw_parts_in<T, A: Allocator>(
23 ptr: NonNull<T>,
24 capacity: usize,
25 allocator: A,
26) -> Heap<T, A> {
27 unsafe {
28 let ptr = std::ptr::slice_from_raw_parts_mut(ptr.as_ptr().cast(), capacity);
29 Box::from_raw_in(ptr, allocator)
30 }
31}
32
33pub(crate) fn box_into_raw_parts_with_alloc<T, A: Allocator>(b: Heap<T, A>) -> (NonNull<T>, usize, A) {
36 let (ptr, alloc) = Box::into_raw_with_allocator(b);
37 unsafe {
38 let (ptr, capacity) = ptr.to_raw_parts();
39 (NonNull::new_unchecked(ptr.cast()), capacity, alloc)
40 }
41}
42
43unsafe impl<T, A: Allocator> Storage for Heap<T, A> {
44 type Item = T;
45
46 fn reserve(&mut self, new_capacity: usize) {
47 if self.len() < new_capacity {
48 let _ = reserve_slow(self, new_capacity, OnFailure::Abort);
49 }
50 }
51
52 fn try_reserve(&mut self, new_capacity: usize) -> AllocResult {
53 if self.len() < new_capacity {
54 reserve_slow(self, new_capacity, OnFailure::Error)
55 } else {
56 Ok(())
57 }
58 }
59}
60
61unsafe impl<T, A: Default + Allocator> StorageWithCapacity for Heap<T, A> {
62 fn with_capacity(cap: usize) -> Self { Box::new_uninit_slice_in(cap, A::default()) }
63}
64
65#[cold]
66#[inline(never)]
67fn reserve_slow<T, A: Allocator>(b: &mut Heap<T, A>, new_capacity: usize, on_failure: OnFailure) -> AllocResult {
68 assert!(new_capacity > b.len());
69
70 let (ptr, cap, alloc) = unsafe { box_into_raw_parts_with_alloc(std::ptr::read(b)) };
74
75 let new_capacity = new_capacity
77 .max(cap.checked_mul(2).expect("Could not grow further"))
78 .max(super::INIT_ALLOC_CAPACITY);
79 let layout = Layout::new::<T>().repeat(new_capacity).expect("Invalid layout").0;
80
81 let ptr = if cap == 0 {
82 unsafe { alloc.allocate(layout) }
83 } else {
84 let new_layout = layout;
85 let old_layout = Layout::new::<T>().repeat(cap).expect("Invalid layout").0;
86
87 unsafe { alloc.grow(ptr.cast(), old_layout, new_layout) }
88 };
89
90 let ptr = match (ptr, on_failure) {
91 (Ok(ptr), _) => ptr,
92 (Err(_), OnFailure::Abort) => handle_alloc_error(layout),
93 (Err(_), OnFailure::Error) => return Err(AllocError),
94 };
95
96 unsafe {
100 let new = box_from_raw_parts_in(ptr.cast(), new_capacity, alloc);
101 let old = std::mem::replace(b, new);
102 std::mem::forget(old);
103 }
104
105 Ok(())
106}