Skip to content

Commit a858499

Browse files
lukas9393Gankra
authored andcommitted
Update vector code examples
The code samples were different from the final code and included deprecated API calls.
1 parent a3180eb commit a858499

File tree

10 files changed

+93
-102
lines changed

10 files changed

+93
-102
lines changed

src/vec-alloc.md

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ want to use `dangling` because there's no real allocation to talk about but
1616
So:
1717

1818
```rust,ignore
19-
#![feature(alloc, heap_api)]
20-
21-
use std::mem;
22-
2319
impl<T> Vec<T> {
2420
fn new() -> Self {
2521
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.
7672

7773
As a simple example, consider the following fragment of code:
7874

79-
```rust
80-
# let x = &mut 0;
81-
# let y = &mut 0;
75+
```rust,ignore
8276
*x *= 7;
8377
*y *= 3;
8478
```
@@ -158,22 +152,18 @@ such we will guard against this case explicitly.
158152
Ok with all the nonsense out of the way, let's actually allocate some memory:
159153

160154
```rust,ignore
161-
use std::alloc::oom;
162-
163155
fn grow(&mut self) {
164156
// this is all pretty delicate, so let's say it's all unsafe
165157
unsafe {
166-
// current API requires us to specify size and alignment manually.
167-
let align = mem::align_of::<T>();
168158
let elem_size = mem::size_of::<T>();
169159
170160
let (new_cap, ptr) = if self.cap == 0 {
171-
let ptr = heap::allocate(elem_size, align);
161+
let ptr = Global.allocate(Layout::array::<T>(1).unwrap());
172162
(1, ptr)
173163
} else {
174164
// as an invariant, we can assume that `self.cap < isize::MAX`,
175165
// so this doesn't need to be checked.
176-
let new_cap = self.cap * 2;
166+
let new_cap = 2 * self.cap;
177167
// Similarly this can't overflow due to previously allocating this
178168
let old_num_bytes = self.cap * elem_size;
179169
@@ -186,23 +176,28 @@ fn grow(&mut self) {
186176
assert!(old_num_bytes <= (isize::MAX as usize) / 2,
187177
"capacity overflow");
188178
189-
let new_num_bytes = old_num_bytes * 2;
190-
let ptr = heap::reallocate(self.ptr.as_ptr() as *mut _,
191-
old_num_bytes,
192-
new_num_bytes,
193-
align);
179+
let c: NonNull<T> = self.ptr.into();
180+
let ptr = Global.grow(c.cast(),
181+
Layout::array::<T>(self.cap).unwrap(),
182+
Layout::array::<T>(new_cap).unwrap());
194183
(new_cap, ptr)
195184
};
196185
197-
// If allocate or reallocate fail, we'll get `null` back
198-
if ptr.is_null() { oom(); }
186+
// If allocate or reallocate fail, oom
187+
if ptr.is_err() {
188+
handle_alloc_error(Layout::from_size_align_unchecked(
189+
new_cap * elem_size,
190+
mem::align_of::<T>(),
191+
))
192+
}
193+
194+
let ptr = ptr.unwrap();
199195
200-
self.ptr = Unique::new(ptr as *mut _);
196+
self.ptr = Unique::new_unchecked(ptr.as_ptr() as *mut _);
201197
self.cap = new_cap;
202198
}
203199
}
204200
```
205201

206202
Nothing particularly tricky here. Just computing sizes and alignments and doing
207203
some careful multiplication checks.
208-

src/vec-dealloc.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ask Rust if `T` `needs_drop` and omit the calls to `pop`. However in practice
77
LLVM is *really* good at removing simple side-effect free code like this, so I
88
wouldn't bother unless you notice it's not being stripped (in this case it is).
99

10-
We must not call `heap::deallocate` when `self.cap == 0`, as in this case we
10+
We must not call `Global.deallocate` when `self.cap == 0`, as in this case we
1111
haven't actually allocated any memory.
1212

1313

@@ -17,11 +17,10 @@ impl<T> Drop for Vec<T> {
1717
if self.cap != 0 {
1818
while let Some(_) = self.pop() { }
1919
20-
let align = mem::align_of::<T>();
21-
let elem_size = mem::size_of::<T>();
22-
let num_bytes = elem_size * self.cap;
2320
unsafe {
24-
heap::deallocate(self.ptr.as_ptr() as *mut _, num_bytes, align);
21+
let c: NonNull<T> = self.ptr.into();
22+
Global.deallocate(c.cast(),
23+
Layout::array::<T>(self.cap).unwrap());
2524
}
2625
}
2726
}

src/vec-drain.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl<'a, T> Iterator for Drain<'a, T> {
2626
-- wait, this is seeming familiar. Let's do some more compression. Both
2727
IntoIter and Drain have the exact same structure, let's just factor it out.
2828

29-
```rust
29+
```rust,ignore
3030
struct RawValIter<T> {
3131
start: *const T,
3232
end: *const T,
@@ -75,7 +75,7 @@ impl<T> DoubleEndedIterator for IntoIter<T> {
7575
7676
impl<T> Drop for IntoIter<T> {
7777
fn drop(&mut self) {
78-
for _ in &mut self.iter {}
78+
for _ in &mut *self {}
7979
}
8080
}
8181
@@ -123,7 +123,7 @@ impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
123123
124124
impl<'a, T> Drop for Drain<'a, T> {
125125
fn drop(&mut self) {
126-
for _ in &mut self.iter {}
126+
for _ in &mut *self {}
127127
}
128128
}
129129

src/vec-final.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ impl<T> Vec<T> {
174174
impl<T> Drop for Vec<T> {
175175
fn drop(&mut self) {
176176
while let Some(_) = self.pop() {}
177-
// allocation is handled by RawVec
177+
// deallocation is handled by RawVec
178178
}
179179
}
180180

@@ -214,7 +214,7 @@ impl<T> RawValIter<T> {
214214
slice.as_ptr()
215215
} else {
216216
slice.as_ptr().offset(slice.len() as isize)
217-
}
217+
},
218218
}
219219
}
220220
}
@@ -307,18 +307,18 @@ impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
307307
impl<'a, T> Drop for Drain<'a, T> {
308308
fn drop(&mut self) {
309309
// pre-drain the iter
310-
for _ in &mut self.iter {}
310+
for _ in &mut *self {}
311311
}
312312
}
313-
313+
#
314314
# fn main() {
315315
# tests::create_push_pop();
316316
# tests::iter_test();
317317
# tests::test_drain();
318318
# tests::test_zst();
319319
# println!("All tests finished OK");
320320
# }
321-
321+
#
322322
# mod tests {
323323
# use super::*;
324324
# pub fn create_push_pop() {

src/vec-insert-remove.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ pub fn insert(&mut self, index: usize, elem: T) {
2222
unsafe {
2323
if index < self.len {
2424
// ptr::copy(src, dest, len): "copy from source to dest len elems"
25-
ptr::copy(self.ptr.offset(index as isize),
26-
self.ptr.offset(index as isize + 1),
25+
ptr::copy(self.ptr.as_ptr().offset(index as isize),
26+
self.ptr.as_ptr().offset(index as isize + 1),
2727
self.len - index);
2828
}
29-
ptr::write(self.ptr.offset(index as isize), elem);
29+
ptr::write(self.ptr.as_ptr().offset(index as isize), elem);
3030
self.len += 1;
3131
}
3232
}
@@ -41,9 +41,9 @@ pub fn remove(&mut self, index: usize) -> T {
4141
assert!(index < self.len, "index out of bounds");
4242
unsafe {
4343
self.len -= 1;
44-
let result = ptr::read(self.ptr.offset(index as isize));
45-
ptr::copy(self.ptr.offset(index as isize + 1),
46-
self.ptr.offset(index as isize),
44+
let result = ptr::read(self.ptr.as_ptr().offset(index as isize));
45+
ptr::copy(self.ptr.as_ptr().offset(index as isize + 1),
46+
self.ptr.as_ptr().offset(index as isize),
4747
self.len - index);
4848
result
4949
}

src/vec-into-iter.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ dropped.
4343
So we're going to use the following struct:
4444

4545
```rust,ignore
46-
struct IntoIter<T> {
46+
pub struct IntoIter<T> {
4747
buf: Unique<T>,
4848
cap: usize,
4949
start: *const T,
@@ -55,7 +55,7 @@ And this is what we end up with for initialization:
5555

5656
```rust,ignore
5757
impl<T> Vec<T> {
58-
fn into_iter(self) -> IntoIter<T> {
58+
pub fn into_iter(self) -> IntoIter<T> {
5959
// Can't destructure Vec since it's Drop
6060
let ptr = self.ptr;
6161
let cap = self.cap;
@@ -68,13 +68,13 @@ impl<T> Vec<T> {
6868
IntoIter {
6969
buf: ptr,
7070
cap: cap,
71-
start: *ptr,
71+
start: ptr.as_ptr(),
7272
end: if cap == 0 {
7373
// can't offset off this pointer, it's not allocated!
74-
*ptr
74+
ptr.as_ptr()
7575
} else {
76-
ptr.offset(len as isize)
77-
}
76+
ptr.as_ptr().offset(len as isize)
77+
},
7878
}
7979
}
8080
}
@@ -135,11 +135,10 @@ impl<T> Drop for IntoIter<T> {
135135
// drop any remaining elements
136136
for _ in &mut *self {}
137137
138-
let align = mem::align_of::<T>();
139-
let elem_size = mem::size_of::<T>();
140-
let num_bytes = elem_size * self.cap;
141138
unsafe {
142-
heap::deallocate(self.buf.as_ptr() as *mut _, num_bytes, align);
139+
let c: NonNull<T> = self.buf.into();
140+
Global.deallocate(c.cast(),
141+
Layout::array::<T>(self.cap).unwrap());
143142
}
144143
}
145144
}

src/vec-layout.md

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@ elements that have been initialized.
66

77
Naively, this means we just want this design:
88

9-
```rust
9+
```rust,ignore
1010
pub struct Vec<T> {
1111
ptr: *mut T,
1212
cap: usize,
1313
len: usize,
1414
}
15-
# fn main() {}
1615
```
1716

1817
And indeed this would compile. Unfortunately, it would be incorrect. First, the
@@ -37,7 +36,7 @@ As a recap, Unique is a wrapper around a raw pointer that declares that:
3736
We can implement all of the above requirements except for the last
3837
one in stable Rust:
3938

40-
```rust
39+
```rust,ignore
4140
use std::marker::PhantomData;
4241
use std::ops::Deref;
4342
use std::mem;
@@ -61,27 +60,19 @@ impl<T> Unique<T> {
6160
self.ptr as *mut T
6261
}
6362
}
64-
65-
# fn main() {}
6663
```
6764

6865
Unfortunately the mechanism for stating that your value is non-zero is
6966
unstable and unlikely to be stabilized soon. As such we're just going to
7067
take the hit and use std's Unique:
7168

7269

73-
```rust
74-
#![feature(ptr_internals)]
75-
76-
use std::ptr::{Unique, self};
77-
70+
```rust,ignore
7871
pub struct Vec<T> {
7972
ptr: Unique<T>,
8073
cap: usize,
8174
len: usize,
8275
}
83-
84-
# fn main() {}
8576
```
8677

8778
If you don't care about the null-pointer optimization, then you can use the

src/vec-push-pop.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn push(&mut self, elem: T) {
2222
if self.len == self.cap { self.grow(); }
2323
2424
unsafe {
25-
ptr::write(self.ptr.offset(self.len as isize), elem);
25+
ptr::write(self.ptr.as_ptr().offset(self.len as isize), elem);
2626
}
2727
2828
// Can't fail, we'll OOM first.
@@ -48,7 +48,7 @@ pub fn pop(&mut self) -> Option<T> {
4848
} else {
4949
self.len -= 1;
5050
unsafe {
51-
Some(ptr::read(self.ptr.offset(self.len as isize)))
51+
Some(ptr::read(self.ptr.as_ptr().offset(self.len as isize)))
5252
}
5353
}
5454
}

0 commit comments

Comments
 (0)