Skip to content

Commit 993cad0

Browse files
committed
WIP: reserve/shrink API's
1 parent ecc9554 commit 993cad0

File tree

1 file changed

+79
-12
lines changed

1 file changed

+79
-12
lines changed

src/lib.rs

+79-12
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,83 @@ impl<H, T> HeaderVec<H, T> {
222222
self.ptr = weak.ptr;
223223
}
224224

225+
/// Reserves capacity for at least `additional` more elements to be inserted in the given `HeaderVec`.
226+
#[inline(always)]
227+
pub fn reserve(&mut self, additional: usize) -> Option<*const ()> {
228+
if self.spare_capacity() < additional {
229+
let len = self.len_exact();
230+
unsafe { self.resize_cold(len + additional, false) }
231+
} else {
232+
None
233+
}
234+
}
235+
236+
/// Reserves capacity for exactly `additional` more elements to be inserted in the given `HeaderVec`.
237+
#[inline]
238+
pub fn reserve_exact(&mut self, additional: usize) -> Option<*const ()> {
239+
if self.spare_capacity() < additional {
240+
let len = self.len_exact();
241+
unsafe { self.resize_cold(len + additional, true) }
242+
} else {
243+
None
244+
}
245+
}
246+
247+
/// Shrinks the capacity of the `HeaderVec` to the `min_capacity` or `self.len()`, whichever is larger.
248+
#[inline]
249+
pub fn shrink_to(&mut self, min_capacity: usize) -> Option<*const ()> {
250+
let requested_capacity = self.len_exact().max(min_capacity);
251+
unsafe { self.resize_cold(requested_capacity, true) }
252+
}
253+
254+
/// Resizes the vector hold exactly `self.len()` elements.
255+
#[inline(always)]
256+
pub fn shrink_to_fit(&mut self) -> Option<*const ()> {
257+
let len = self.len_exact();
258+
self.shrink_to(len)
259+
}
260+
261+
/// Resize the vector to have at least room for `additional` more elements.
262+
/// does exact resizing if `exact` is true.
263+
///
264+
/// Returns `Some(*const ())` if the memory was moved to a new location.
265+
///
266+
/// # Safety
267+
///
268+
/// `requested_capacity` must be greater or equal than `self.len()`
225269
#[cold]
226-
fn resize_insert(&mut self) -> Option<*const ()> {
270+
unsafe fn resize_cold(&mut self, requested_capacity: usize, exact: bool) -> Option<*const ()> {
271+
// For efficiency we do only a debug_assert here
272+
debug_assert!(
273+
self.len_exact() <= requested_capacity,
274+
"requested capacity is less than current length"
275+
);
227276
let old_capacity = self.capacity();
228-
let new_capacity = old_capacity * 2;
229-
// Set the new capacity.
230-
self.header_mut().capacity = new_capacity;
277+
debug_assert_ne!(old_capacity, 0, "capacity of 0 not yet supported");
278+
debug_assert_ne!(requested_capacity, 0, "capacity of 0 not yet supported");
279+
280+
let new_capacity = if requested_capacity > old_capacity {
281+
if exact {
282+
// exact growing
283+
requested_capacity
284+
} else if requested_capacity <= old_capacity * 2 {
285+
// doubling the capacity is sufficient
286+
old_capacity * 2
287+
} else {
288+
// requested more than twice as much space, reserve the next multiple of
289+
// old_capacity that is greater than the requested capacity. This gives headroom
290+
// for new inserts while not doubling the memory requirement with bulk requests
291+
(requested_capacity / old_capacity + 1).saturating_mul(old_capacity)
292+
}
293+
} else if exact {
294+
// exact shrinking
295+
requested_capacity
296+
} else {
297+
unimplemented!()
298+
// or: (has no public API yet)
299+
// // shrink to the next power of two or self.capacity, whichever is smaller
300+
// requested_capacity.next_power_of_two().min(self.capacity())
301+
};
231302
// Reallocate the pointer.
232303
let ptr = unsafe {
233304
alloc::alloc::realloc(
@@ -249,24 +320,20 @@ impl<H, T> HeaderVec<H, T> {
249320
};
250321
// Assign the new pointer.
251322
self.ptr = ptr;
323+
// And set the new capacity.
324+
self.header_mut().capacity = new_capacity;
252325

253326
previous_pointer
254327
}
255328

256329
/// Adds an item to the end of the list.
257330
///
258-
/// Returns `true` if the memory was moved to a new location.
331+
/// Returns `Some(*const ())` if the memory was moved to a new location.
259332
/// In this case, you are responsible for updating the weak nodes.
260333
pub fn push(&mut self, item: T) -> Option<*const ()> {
261334
let old_len = self.len_exact();
262335
let new_len = old_len + 1;
263-
let old_capacity = self.capacity();
264-
// If it isn't big enough.
265-
let previous_pointer = if new_len > old_capacity {
266-
self.resize_insert()
267-
} else {
268-
None
269-
};
336+
let previous_pointer = self.reserve(1);
270337
unsafe {
271338
core::ptr::write(self.start_ptr_mut().add(old_len), item);
272339
}

0 commit comments

Comments
 (0)