2020-06-04 16:39:33 -04:00
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
|
|
|
2020-06-19 02:36:42 -04:00
|
|
|
/// Dynamically updated size hint
|
2020-07-09 19:50:32 -04:00
|
|
|
#[doc(hidden)]
|
2020-06-04 16:39:33 -04:00
|
|
|
pub struct SizeHint {
|
|
|
|
value: AtomicUsize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SizeHint {
|
2020-12-20 07:20:52 -05:00
|
|
|
/// Initialize size hint
|
2020-06-04 16:39:33 -04:00
|
|
|
pub const fn new() -> SizeHint {
|
|
|
|
SizeHint {
|
|
|
|
value: AtomicUsize::new(0),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the current value
|
|
|
|
#[inline]
|
|
|
|
pub fn get(&self) -> usize {
|
2020-12-20 06:21:18 -05:00
|
|
|
let value = self.value.load(Ordering::Acquire);
|
|
|
|
value + value / 8 + 75
|
2020-06-04 16:39:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Update size hint based on given value.
|
|
|
|
///
|
|
|
|
/// There is no guarantee that the value of get() after calling update() is same
|
|
|
|
/// as the value passed on update()
|
|
|
|
#[inline]
|
2020-12-20 06:21:18 -05:00
|
|
|
pub fn update(&self, value: usize) {
|
|
|
|
let mut old = self.value.load(Ordering::Acquire);
|
|
|
|
if old == 0 {
|
|
|
|
old = value;
|
2020-06-04 16:39:33 -04:00
|
|
|
}
|
2020-12-20 06:21:18 -05:00
|
|
|
self.value
|
|
|
|
.store(old - old / 4 + value / 4, Ordering::Release);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_update() {
|
|
|
|
let hint = SizeHint::new();
|
|
|
|
|
|
|
|
for size in 1..=100 {
|
|
|
|
let cap = hint.get();
|
|
|
|
assert!(size <= cap);
|
|
|
|
assert!(cap <= size + size / 8 + 75);
|
|
|
|
hint.update(size);
|
2020-06-04 16:39:33 -04:00
|
|
|
}
|
|
|
|
}
|