Skip to content

Commit c2026c2

Browse files
committed
WIP: introduce WeakFixupFn, start removing Option<*const ()>
This introduce a breaking change starting to modifying all methods that indicate a realloc by returning a Option(*const()) into stdlib compatible signatures and variants taking a closure for the fixup. This commits starts with reserve and shrink methods, more in the following commits. The `WeakFixupFn` is required for Drain and other iterators which do significant work in the destructor (possibly reallocating the headervec there). The closure can be passed along and called when required. Compatibility note: When it is not trivially possible to refactor fixup functionality to a closure then old code can be migrated by: let maybe_realloc: Option<*const ()> = { let mut opt_ptr = None; hv.reserve_with_weakfix(&mut self, 10000, |ptr| opt_ptr = Some(ptr)); opt_ptr }; // now maybe_realloc is like the old Option<*const ()> return if let Some(ptr) = maybe_realloc { // fixup code using ptr } Note 2: do we want legacy wrapper functions that have the old behavior eg. #[deprecated("upgrade to the new API")] pub fn reserve_legacy(&mut self, additional: usize) -> Option<*const ()> { let mut opt_ptr = None; self.reserve_with_weakfix(additional, |ptr| opt_ptr = Some(ptr)); opt_ptr };
1 parent 47af90f commit c2026c2

1 file changed

Lines changed: 66 additions & 23 deletions

File tree

src/lib.rs

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ use core::{
1414
#[cfg(feature = "atomic_append")]
1515
use core::sync::atomic::{AtomicUsize, Ordering};
1616

17+
/// A closure that becomes called when a `HeaderVec` becomes reallocated.
18+
/// This is closure is responsible for updating weak nodes.
19+
pub type WeakFixupFn<'a> = &'a mut dyn FnMut(*const ());
20+
1721
struct HeaderVecHeader<H> {
1822
head: H,
1923
capacity: usize,
@@ -220,39 +224,72 @@ impl<H, T> HeaderVec<H, T> {
220224
}
221225

222226
/// Reserves capacity for at least `additional` more elements to be inserted in the given `HeaderVec`.
223-
#[inline(always)]
224-
pub fn reserve(&mut self, additional: usize) -> Option<*const ()> {
225-
if self.spare_capacity() < additional {
226-
let len = self.len_exact();
227-
unsafe { self.resize_cold(len.saturating_add(additional), false) }
228-
} else {
229-
None
230-
}
227+
#[inline]
228+
pub fn reserve(&mut self, additional: usize) {
229+
self.reserve_intern(additional, false, None);
230+
}
231+
232+
/// Reserves capacity for at least `additional` more elements to be inserted in the given `HeaderVec`.
233+
/// This method must be used when `HeaderVecWeak` are used. It takes a closure that is responsible for
234+
/// updating the weak references as additional parameter.
235+
#[inline]
236+
pub fn reserve_with_weakfix(&mut self, additional: usize, weak_fixup: WeakFixupFn) {
237+
self.reserve_intern(additional, false, Some(weak_fixup));
238+
}
239+
240+
/// Reserves capacity for exactly `additional` more elements to be inserted in the given `HeaderVec`.
241+
#[inline]
242+
pub fn reserve_exact(&mut self, additional: usize) {
243+
self.reserve_intern(additional, true, None);
231244
}
232245

233246
/// Reserves capacity for exactly `additional` more elements to be inserted in the given `HeaderVec`.
247+
/// This method must be used when `HeaderVecWeak` are used. It takes a closure that is responsible for
248+
/// updating the weak references as additional parameter.
234249
#[inline]
235-
pub fn reserve_exact(&mut self, additional: usize) -> Option<*const ()> {
250+
pub fn reserve_exact_with_weakfix(&mut self, additional: usize, weak_fixup: WeakFixupFn) {
251+
self.reserve_intern(additional, true, Some(weak_fixup));
252+
}
253+
254+
/// Reserves capacity for at least `additional` more elements to be inserted in the given `HeaderVec`.
255+
#[inline(always)]
256+
fn reserve_intern(&mut self, additional: usize, exact: bool, weak_fixup: Option<WeakFixupFn>) {
236257
if self.spare_capacity() < additional {
237258
let len = self.len_exact();
238-
unsafe { self.resize_cold(len.saturating_add(additional), true) }
239-
} else {
240-
None
259+
// using saturating_add here ensures that we get a allocation error instead wrapping over and
260+
// allocating a total wrong size
261+
unsafe { self.resize_cold(len.saturating_add(additional), exact, weak_fixup) };
241262
}
242263
}
243264

244265
/// Shrinks the capacity of the `HeaderVec` to the `min_capacity` or `self.len()`, whichever is larger.
245266
#[inline]
246-
pub fn shrink_to(&mut self, min_capacity: usize) -> Option<*const ()> {
267+
pub fn shrink_to(&mut self, min_capacity: usize) {
247268
let requested_capacity = self.len_exact().max(min_capacity);
248-
unsafe { self.resize_cold(requested_capacity, true) }
269+
unsafe { self.resize_cold(requested_capacity, true, None) };
270+
}
271+
272+
/// Shrinks the capacity of the `HeaderVec` to the `min_capacity` or `self.len()`, whichever is larger.
273+
/// This method must be used when `HeaderVecWeak` are used. It takes a closure that is responsible for
274+
/// updating the weak references as additional parameter.
275+
#[inline]
276+
pub fn shrink_to_with_weakfix(&mut self, min_capacity: usize, weak_fixup: WeakFixupFn) {
277+
let requested_capacity = self.len_exact().max(min_capacity);
278+
unsafe { self.resize_cold(requested_capacity, true, Some(weak_fixup)) };
279+
}
280+
281+
/// Resizes the vector hold exactly `self.len()` elements.
282+
#[inline(always)]
283+
pub fn shrink_to_fit(&mut self) {
284+
self.shrink_to(0);
249285
}
250286

251287
/// Resizes the vector hold exactly `self.len()` elements.
288+
/// This method must be used when `HeaderVecWeak` are used. It takes a closure that is responsible for
289+
/// updating the weak references as additional parameter.
252290
#[inline(always)]
253-
pub fn shrink_to_fit(&mut self) -> Option<*const ()> {
254-
let len = self.len_exact();
255-
self.shrink_to(len)
291+
pub fn shrink_to_fit_with_weakfix(&mut self, weak_fixup: WeakFixupFn) {
292+
self.shrink_to_with_weakfix(0, weak_fixup);
256293
}
257294

258295
/// Resize the vector to least `requested_capacity` elements.
@@ -264,7 +301,12 @@ impl<H, T> HeaderVec<H, T> {
264301
///
265302
/// `requested_capacity` must be greater or equal than `self.len()`
266303
#[cold]
267-
unsafe fn resize_cold(&mut self, requested_capacity: usize, exact: bool) -> Option<*const ()> {
304+
unsafe fn resize_cold(
305+
&mut self,
306+
requested_capacity: usize,
307+
exact: bool,
308+
weak_fixup: Option<WeakFixupFn>,
309+
) {
268310
// For efficiency we do only a debug_assert here, this is a internal unsafe function
269311
// it's contract should be already enforced by the caller which is under our control
270312
debug_assert!(
@@ -275,7 +317,7 @@ impl<H, T> HeaderVec<H, T> {
275317

276318
// Shortcut when nothing is to be done.
277319
if requested_capacity == old_capacity {
278-
return None;
320+
return;
279321
}
280322

281323
let new_capacity = if requested_capacity > old_capacity {
@@ -319,7 +361,7 @@ impl<H, T> HeaderVec<H, T> {
319361

320362
// Check if the new pointer is different than the old one.
321363
let previous_pointer = if ptr != self.ptr {
322-
// Give the user the old pointer so they can update everything.
364+
// Store old pointer for weak_fixup.
323365
Some(self.ptr())
324366
} else {
325367
None
@@ -329,7 +371,8 @@ impl<H, T> HeaderVec<H, T> {
329371
// And set the new capacity.
330372
self.header_mut().capacity = new_capacity;
331373

332-
previous_pointer
374+
// Finally run the weak_fixup closure when provided
375+
previous_pointer.map(|ptr| weak_fixup.map(|weak_fixup| weak_fixup(ptr)));
333376
}
334377

335378
/// Adds an item to the end of the list.
@@ -344,7 +387,7 @@ impl<H, T> HeaderVec<H, T> {
344387
core::ptr::write(self.as_mut_ptr().add(old_len), item);
345388
}
346389
self.header_mut().len = new_len.into();
347-
previous_pointer
390+
todo!("weak_fixup transformartion") // previous_pointer
348391
}
349392

350393
/// Retains only the elements specified by the predicate.
@@ -497,7 +540,7 @@ impl<H, T: Clone> HeaderVec<H, T> {
497540
// correct the len
498541
self.header_mut().len = (self.len_exact() + slice.len()).into();
499542

500-
previous_pointer
543+
todo!("weak_fixup transformartion") // previous_pointer
501544
}
502545
}
503546

0 commit comments

Comments
 (0)