Skip to content

Commit 67ea343

Browse files
committed
Combine Rc and Vec allocation into one allocation
1 parent a2b46f9 commit 67ea343

1 file changed

Lines changed: 206 additions & 40 deletions

File tree

src/rcvec.rs

Lines changed: 206 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,238 @@
1+
use std::alloc::{self, Layout};
2+
use std::cell::Cell;
3+
use std::cmp;
14
use std::mem;
2-
use std::rc::Rc;
5+
use std::process;
6+
use std::ptr;
37
use std::slice;
4-
use std::vec;
8+
9+
struct Header {
10+
cap: usize,
11+
len: usize,
12+
refcount: Cell<usize>,
13+
}
514

615
pub(crate) struct RcVec<T> {
7-
inner: Rc<Vec<T>>,
16+
first: *mut T,
817
}
918

1019
pub(crate) struct RcVecBuilder<T> {
11-
inner: Vec<T>,
20+
first: *mut T,
1221
}
1322

1423
pub(crate) struct RcVecMut<'a, T> {
15-
inner: &'a mut Vec<T>,
24+
first: &'a mut *mut T,
1625
}
1726

1827
#[derive(Clone)]
1928
pub(crate) struct RcVecIntoIter<T> {
20-
inner: vec::IntoIter<T>,
29+
first: *mut T,
30+
cur: *mut T,
31+
}
32+
33+
unsafe fn header<'a, T>(first: *mut T) -> &'a Header {
34+
&*(first as *const Header).offset(-1)
35+
}
36+
37+
unsafe fn header_mut<'a, T>(first: *mut T) -> &'a mut Header {
38+
&mut *(first as *mut Header).offset(-1)
39+
}
40+
41+
unsafe fn allocation_layout<T>(first: *mut T) -> (*mut u8, Layout) {
42+
// Alignment of the allocation.
43+
let align = cmp::max(mem::align_of::<T>(), mem::align_of::<Header>());
44+
45+
// Round up Header's size to a multiple of allocation's alignment.
46+
let mut header_size = mem::size_of::<Header>();
47+
header_size = (header_size + align - 1) / align * align;
48+
49+
let allocation = (first as *mut u8).sub(header_size);
50+
let total_size = header_size + header(first).cap * mem::size_of::<T>();
51+
let layout = Layout::from_size_align_unchecked(total_size, align);
52+
(allocation, layout)
2153
}
2254

2355
impl<T> RcVec<T> {
2456
pub fn is_empty(&self) -> bool {
25-
self.inner.is_empty()
57+
self.len() == 0
2658
}
2759

2860
pub fn len(&self) -> usize {
29-
self.inner.len()
61+
self.header().len
3062
}
3163

3264
pub fn iter(&self) -> slice::Iter<T> {
33-
self.inner.iter()
65+
let len = self.len();
66+
unsafe { slice::from_raw_parts(self.first, len) }.iter()
3467
}
3568

3669
pub fn make_mut(&mut self) -> RcVecMut<T>
3770
where
3871
T: Clone,
3972
{
73+
let header = self.header();
74+
let refcount = header.refcount.get();
75+
if refcount > 1 {
76+
let mut builder = RcVecBuilder::new();
77+
builder.extend(self.iter().cloned());
78+
// NOTE: assumes that none of the clones on the previous line
79+
// resulted in self's refcount changing. The public API of RcVec
80+
// does not expose any way to form cyclic structures.
81+
header.refcount.set(refcount - 1);
82+
self.first = builder.first;
83+
mem::forget(builder);
84+
}
4085
RcVecMut {
41-
inner: Rc::make_mut(&mut self.inner),
86+
first: &mut self.first,
4287
}
4388
}
4489

4590
pub fn get_mut(&mut self) -> Option<RcVecMut<T>> {
46-
let inner = Rc::get_mut(&mut self.inner)?;
47-
Some(RcVecMut { inner })
91+
if self.header().refcount.get() > 1 {
92+
None
93+
} else {
94+
Some(RcVecMut {
95+
first: &mut self.first,
96+
})
97+
}
4898
}
4999

50-
pub fn make_owned(mut self) -> RcVecBuilder<T>
100+
pub fn make_owned(self) -> RcVecBuilder<T>
51101
where
52102
T: Clone,
53103
{
54-
let vec = if let Some(owned) = Rc::get_mut(&mut self.inner) {
55-
mem::replace(owned, Vec::new())
104+
let header = self.header();
105+
let refcount = header.refcount.get();
106+
let first;
107+
if refcount > 1 {
108+
let mut builder = RcVecBuilder::new();
109+
builder.extend(self.iter().cloned());
110+
header.refcount.set(refcount - 1);
111+
first = builder.first;
112+
mem::forget(builder);
56113
} else {
57-
Vec::clone(&self.inner)
58-
};
59-
RcVecBuilder { inner: vec }
114+
first = self.first;
115+
}
116+
mem::forget(self);
117+
RcVecBuilder { first }
118+
}
119+
120+
fn header(&self) -> &Header {
121+
unsafe { header(self.first) }
60122
}
61123
}
62124

63125
impl<T> RcVecBuilder<T> {
64126
pub fn new() -> Self {
65-
RcVecBuilder { inner: Vec::new() }
127+
Self::with_capacity(8)
66128
}
67129

68130
pub fn with_capacity(cap: usize) -> Self {
69-
RcVecBuilder {
70-
inner: Vec::with_capacity(cap),
131+
assert!(mem::size_of::<T>() > 0);
132+
133+
// Alignment of the allocation.
134+
let align = cmp::max(mem::align_of::<T>(), mem::align_of::<Header>());
135+
136+
// Round up Header's size to a multiple of allocation's alignment.
137+
let mut header_size = mem::size_of::<Header>();
138+
header_size = (header_size + align - 1) / align * align;
139+
140+
let total_size = mem::size_of::<T>()
141+
.saturating_mul(cap)
142+
.saturating_add(header_size);
143+
let layout = match Layout::from_size_align(total_size, align) {
144+
Ok(layout) => layout,
145+
Err(_) => process::abort(),
146+
};
147+
148+
unsafe {
149+
let ptr = alloc::alloc(layout);
150+
let first = ptr.add(header_size) as *mut T;
151+
(first as *mut Header).offset(-1).write(Header {
152+
cap,
153+
len: 0,
154+
refcount: Cell::new(1),
155+
});
156+
RcVecBuilder { first }
71157
}
72158
}
73159

74160
pub fn push(&mut self, element: T) {
75-
self.inner.push(element);
161+
self.as_mut().push(element);
76162
}
77163

78164
pub fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
79-
self.inner.extend(iter);
165+
self.as_mut().extend(iter);
80166
}
81167

82168
pub fn as_mut(&mut self) -> RcVecMut<T> {
83169
RcVecMut {
84-
inner: &mut self.inner,
170+
first: &mut self.first,
85171
}
86172
}
87173

88174
pub fn build(self) -> RcVec<T> {
89-
RcVec {
90-
inner: Rc::new(self.inner),
91-
}
175+
let first = self.first;
176+
mem::forget(self);
177+
RcVec { first }
92178
}
93179
}
94180

95181
impl<'a, T> RcVecMut<'a, T> {
96182
pub fn push(&mut self, element: T) {
97-
self.inner.push(element);
183+
self.reserve(1);
184+
let header = unsafe { header_mut(*self.first) };
185+
unsafe { ptr::write(self.first.add(header.len), element) };
186+
header.len += 1;
98187
}
99188

100-
pub fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
101-
self.inner.extend(iter);
189+
pub fn extend(&mut self, elements: impl IntoIterator<Item = T>) {
190+
let iter = elements.into_iter();
191+
self.reserve(iter.size_hint().0);
192+
iter.for_each(|element| self.push(element));
102193
}
103194

104195
pub fn pop(&mut self) -> Option<T> {
105-
self.inner.pop()
196+
unsafe {
197+
let header = header_mut(*self.first);
198+
header.len = header.len.checked_sub(1)?;
199+
Some(ptr::read(self.first.add(header.len)))
200+
}
106201
}
107202

108203
pub fn as_mut(&mut self) -> RcVecMut<T> {
109-
RcVecMut { inner: self.inner }
204+
RcVecMut { first: self.first }
205+
}
206+
207+
fn reserve(&mut self, additional: usize) {
208+
let header = unsafe { header(*self.first) };
209+
let required_capacity = header.len.saturating_add(additional);
210+
if header.cap >= required_capacity {
211+
return;
212+
}
213+
214+
let min_new_capacity = cmp::max(8, header.cap.saturating_mul(2));
215+
let new_capacity = cmp::max(required_capacity, min_new_capacity);
216+
217+
// Move ownership of the old allocation.
218+
let small = RcVecBuilder { first: *self.first };
219+
220+
// Move elements into new allocation.
221+
let mut big = RcVecBuilder::with_capacity(new_capacity);
222+
big.extend(small.into_iter());
223+
224+
// Self becomes big.
225+
*self.first = big.first;
226+
mem::forget(big);
110227
}
111228
}
112229

113230
impl<T> Clone for RcVec<T> {
114231
fn clone(&self) -> Self {
115-
RcVec {
116-
inner: Rc::clone(&self.inner),
117-
}
232+
let header = self.header();
233+
let count = header.refcount.get().checked_add(1).unwrap();
234+
header.refcount.set(count);
235+
RcVec { first: self.first }
118236
}
119237
}
120238

@@ -123,20 +241,68 @@ impl<T> IntoIterator for RcVecBuilder<T> {
123241
type IntoIter = RcVecIntoIter<T>;
124242

125243
fn into_iter(self) -> Self::IntoIter {
126-
RcVecIntoIter {
127-
inner: self.inner.into_iter(),
128-
}
244+
let first = self.first;
245+
mem::forget(self);
246+
RcVecIntoIter { first, cur: first }
129247
}
130248
}
131249

132250
impl<T> Iterator for RcVecIntoIter<T> {
133251
type Item = T;
134252

135253
fn next(&mut self) -> Option<Self::Item> {
136-
self.inner.next()
254+
unsafe {
255+
let len = header(self.first).len;
256+
if self.cur < self.first.add(len) {
257+
let element = ptr::read(self.cur);
258+
self.cur = self.cur.add(1);
259+
Some(element)
260+
} else {
261+
None
262+
}
263+
}
137264
}
138265

139266
fn size_hint(&self) -> (usize, Option<usize>) {
140-
self.inner.size_hint()
267+
let end = unsafe { self.first.add(header(self.first).len) };
268+
let remaining = (end as usize - self.cur as usize) / mem::size_of::<T>();
269+
(remaining, Some(remaining))
270+
}
271+
}
272+
273+
impl<T> Drop for RcVec<T> {
274+
fn drop(&mut self) {
275+
let header = self.header();
276+
let refcount = header.refcount.get();
277+
if refcount > 1 {
278+
header.refcount.set(refcount - 1);
279+
} else {
280+
drop(RcVecBuilder { first: self.first });
281+
}
282+
}
283+
}
284+
285+
impl<T> Drop for RcVecBuilder<T> {
286+
fn drop(&mut self) {
287+
unsafe {
288+
let len = header(self.first).len;
289+
let slice = slice::from_raw_parts_mut(self.first, len);
290+
ptr::drop_in_place(slice);
291+
let (ptr, layout) = allocation_layout(self.first);
292+
alloc::dealloc(ptr, layout);
293+
}
294+
}
295+
}
296+
297+
impl<T> Drop for RcVecIntoIter<T> {
298+
fn drop(&mut self) {
299+
unsafe {
300+
let len = header(self.first).len;
301+
let offset = (self.cur as usize - self.first as usize) / mem::size_of::<T>();
302+
let slice = slice::from_raw_parts_mut(self.cur, len - offset);
303+
ptr::drop_in_place(slice);
304+
let (ptr, layout) = allocation_layout(self.first);
305+
alloc::dealloc(ptr, layout);
306+
}
141307
}
142308
}

0 commit comments

Comments
 (0)