|
|
@ -16,10 +16,6 @@ want to use `dangling` because there's no real allocation to talk about but
|
|
|
|
So:
|
|
|
|
So:
|
|
|
|
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
```rust,ignore
|
|
|
|
#![feature(alloc, heap_api)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use std::mem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<T> Vec<T> {
|
|
|
|
impl<T> Vec<T> {
|
|
|
|
fn new() -> Self {
|
|
|
|
fn new() -> Self {
|
|
|
|
assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");
|
|
|
|
assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");
|
|
|
@ -76,9 +72,7 @@ compiler to be able to reason about data dependencies and aliasing.
|
|
|
|
|
|
|
|
|
|
|
|
As a simple example, consider the following fragment of code:
|
|
|
|
As a simple example, consider the following fragment of code:
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
```rust,ignore
|
|
|
|
# let x = &mut 0;
|
|
|
|
|
|
|
|
# let y = &mut 0;
|
|
|
|
|
|
|
|
*x *= 7;
|
|
|
|
*x *= 7;
|
|
|
|
*y *= 3;
|
|
|
|
*y *= 3;
|
|
|
|
```
|
|
|
|
```
|
|
|
@ -158,22 +152,18 @@ such we will guard against this case explicitly.
|
|
|
|
Ok with all the nonsense out of the way, let's actually allocate some memory:
|
|
|
|
Ok with all the nonsense out of the way, let's actually allocate some memory:
|
|
|
|
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
```rust,ignore
|
|
|
|
use std::alloc::oom;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn grow(&mut self) {
|
|
|
|
fn grow(&mut self) {
|
|
|
|
// this is all pretty delicate, so let's say it's all unsafe
|
|
|
|
// this is all pretty delicate, so let's say it's all unsafe
|
|
|
|
unsafe {
|
|
|
|
unsafe {
|
|
|
|
// current API requires us to specify size and alignment manually.
|
|
|
|
|
|
|
|
let align = mem::align_of::<T>();
|
|
|
|
|
|
|
|
let elem_size = mem::size_of::<T>();
|
|
|
|
let elem_size = mem::size_of::<T>();
|
|
|
|
|
|
|
|
|
|
|
|
let (new_cap, ptr) = if self.cap == 0 {
|
|
|
|
let (new_cap, ptr) = if self.cap == 0 {
|
|
|
|
let ptr = heap::allocate(elem_size, align);
|
|
|
|
let ptr = Global.allocate(Layout::array::<T>(1).unwrap());
|
|
|
|
(1, ptr)
|
|
|
|
(1, ptr)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// as an invariant, we can assume that `self.cap < isize::MAX`,
|
|
|
|
// as an invariant, we can assume that `self.cap < isize::MAX`,
|
|
|
|
// so this doesn't need to be checked.
|
|
|
|
// so this doesn't need to be checked.
|
|
|
|
let new_cap = self.cap * 2;
|
|
|
|
let new_cap = 2 * self.cap;
|
|
|
|
// Similarly this can't overflow due to previously allocating this
|
|
|
|
// Similarly this can't overflow due to previously allocating this
|
|
|
|
let old_num_bytes = self.cap * elem_size;
|
|
|
|
let old_num_bytes = self.cap * elem_size;
|
|
|
|
|
|
|
|
|
|
|
@ -186,18 +176,24 @@ fn grow(&mut self) {
|
|
|
|
assert!(old_num_bytes <= (isize::MAX as usize) / 2,
|
|
|
|
assert!(old_num_bytes <= (isize::MAX as usize) / 2,
|
|
|
|
"capacity overflow");
|
|
|
|
"capacity overflow");
|
|
|
|
|
|
|
|
|
|
|
|
let new_num_bytes = old_num_bytes * 2;
|
|
|
|
let c: NonNull<T> = self.ptr.into();
|
|
|
|
let ptr = heap::reallocate(self.ptr.as_ptr() as *mut _,
|
|
|
|
let ptr = Global.grow(c.cast(),
|
|
|
|
old_num_bytes,
|
|
|
|
Layout::array::<T>(self.cap).unwrap(),
|
|
|
|
new_num_bytes,
|
|
|
|
Layout::array::<T>(new_cap).unwrap());
|
|
|
|
align);
|
|
|
|
|
|
|
|
(new_cap, ptr)
|
|
|
|
(new_cap, ptr)
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// If allocate or reallocate fail, we'll get `null` back
|
|
|
|
// If allocate or reallocate fail, oom
|
|
|
|
if ptr.is_null() { oom(); }
|
|
|
|
if ptr.is_err() {
|
|
|
|
|
|
|
|
handle_alloc_error(Layout::from_size_align_unchecked(
|
|
|
|
|
|
|
|
new_cap * elem_size,
|
|
|
|
|
|
|
|
mem::align_of::<T>(),
|
|
|
|
|
|
|
|
))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let ptr = ptr.unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
self.ptr = Unique::new(ptr as *mut _);
|
|
|
|
self.ptr = Unique::new_unchecked(ptr.as_ptr() as *mut _);
|
|
|
|
self.cap = new_cap;
|
|
|
|
self.cap = new_cap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -205,4 +201,3 @@ fn grow(&mut self) {
|
|
|
|
|
|
|
|
|
|
|
|
Nothing particularly tricky here. Just computing sizes and alignments and doing
|
|
|
|
Nothing particularly tricky here. Just computing sizes and alignments and doing
|
|
|
|
some careful multiplication checks.
|
|
|
|
some careful multiplication checks.
|
|
|
|
|
|
|
|
|
|
|
|