]> git.proxmox.com Git - rustc.git/blame - src/doc/nomicon/src/vec-raw.md
New upstream version 1.50.0+dfsg1
[rustc.git] / src / doc / nomicon / src / vec-raw.md
CommitLineData
7cac9316 1
8bb4bdeb 2# RawVec
c1a9b12d
SL
3
4We've actually reached an interesting situation here: we've duplicated the logic
5for specifying a buffer and freeing its memory in Vec and IntoIter. Now that
6we've implemented it and identified *actual* logic duplication, this is a good
7time to perform some logic compression.
8
9We're going to abstract out the `(ptr, cap)` pair and give them the logic for
10allocating, growing, and freeing:
11
12```rust,ignore
13struct RawVec<T> {
14 ptr: Unique<T>,
15 cap: usize,
16}
17
18impl<T> RawVec<T> {
19 fn new() -> Self {
20 assert!(mem::size_of::<T>() != 0, "TODO: implement ZST support");
f9f354fc 21 RawVec { ptr: Unique::dangling(), cap: 0 }
c1a9b12d
SL
22 }
23
24 // unchanged from Vec
25 fn grow(&mut self) {
26 unsafe {
27 let align = mem::align_of::<T>();
28 let elem_size = mem::size_of::<T>();
29
30 let (new_cap, ptr) = if self.cap == 0 {
31 let ptr = heap::allocate(elem_size, align);
32 (1, ptr)
33 } else {
34 let new_cap = 2 * self.cap;
7cac9316 35 let ptr = heap::reallocate(self.ptr.as_ptr() as *mut _,
c1a9b12d
SL
36 self.cap * elem_size,
37 new_cap * elem_size,
38 align);
39 (new_cap, ptr)
40 };
41
42 // If allocate or reallocate fail, we'll get `null` back
43 if ptr.is_null() { oom() }
44
45 self.ptr = Unique::new(ptr as *mut _);
46 self.cap = new_cap;
47 }
48 }
49}
50
51
52impl<T> Drop for RawVec<T> {
53 fn drop(&mut self) {
54 if self.cap != 0 {
55 let align = mem::align_of::<T>();
56 let elem_size = mem::size_of::<T>();
57 let num_bytes = elem_size * self.cap;
58 unsafe {
7cac9316 59 heap::deallocate(self.ptr.as_mut() as *mut _, num_bytes, align);
c1a9b12d
SL
60 }
61 }
62 }
63}
64```
65
66And change Vec as follows:
67
68```rust,ignore
69pub struct Vec<T> {
70 buf: RawVec<T>,
71 len: usize,
72}
73
74impl<T> Vec<T> {
7cac9316 75 fn ptr(&self) -> *mut T { self.buf.ptr.as_ptr() }
c1a9b12d
SL
76
77 fn cap(&self) -> usize { self.buf.cap }
78
79 pub fn new() -> Self {
80 Vec { buf: RawVec::new(), len: 0 }
81 }
82
83 // push/pop/insert/remove largely unchanged:
84 // * `self.ptr -> self.ptr()`
85 // * `self.cap -> self.cap()`
86 // * `self.grow -> self.buf.grow()`
87}
88
89impl<T> Drop for Vec<T> {
90 fn drop(&mut self) {
91 while let Some(_) = self.pop() {}
92 // deallocation is handled by RawVec
93 }
94}
95```
96
97And finally we can really simplify IntoIter:
98
99```rust,ignore
100struct IntoIter<T> {
101 _buf: RawVec<T>, // we don't actually care about this. Just need it to live.
102 start: *const T,
103 end: *const T,
104}
105
106// next and next_back literally unchanged since they never referred to the buf
107
108impl<T> Drop for IntoIter<T> {
109 fn drop(&mut self) {
110 // only need to ensure all our elements are read;
111 // buffer will clean itself up afterwards.
112 for _ in &mut *self {}
113 }
114}
115
116impl<T> Vec<T> {
117 pub fn into_iter(self) -> IntoIter<T> {
118 unsafe {
119 // need to use ptr::read to unsafely move the buf out since it's
120 // not Copy, and Vec implements Drop (so we can't destructure it).
121 let buf = ptr::read(&self.buf);
122 let len = self.len;
123 mem::forget(self);
124
125 IntoIter {
126 start: *buf.ptr,
127 end: buf.ptr.offset(len as isize),
128 _buf: buf,
129 }
130 }
131 }
132}
133```
134
135Much better.