]>
Commit | Line | Data |
---|---|---|
7cac9316 | 1 | |
8bb4bdeb | 2 | # RawVec |
c1a9b12d SL |
3 | |
4 | We've actually reached an interesting situation here: we've duplicated the logic | |
5 | for specifying a buffer and freeing its memory in Vec and IntoIter. Now that | |
6 | we've implemented it and identified *actual* logic duplication, this is a good | |
7 | time to perform some logic compression. | |
8 | ||
9 | We're going to abstract out the `(ptr, cap)` pair and give them the logic for | |
10 | allocating, growing, and freeing: | |
11 | ||
12 | ```rust,ignore | |
13 | struct RawVec<T> { | |
14 | ptr: Unique<T>, | |
15 | cap: usize, | |
16 | } | |
17 | ||
18 | impl<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 | ||
52 | impl<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 | ||
66 | And change Vec as follows: | |
67 | ||
68 | ```rust,ignore | |
69 | pub struct Vec<T> { | |
70 | buf: RawVec<T>, | |
71 | len: usize, | |
72 | } | |
73 | ||
74 | impl<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 | ||
89 | impl<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 | ||
97 | And finally we can really simplify IntoIter: | |
98 | ||
99 | ```rust,ignore | |
100 | struct 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 | ||
108 | impl<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 | ||
116 | impl<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 | ||
135 | Much better. |