Skip to main content

cranpose_core/collections/
growth_slack.rs

1//! Giving back the room a collection's growth left past its items: a
2//! collection that lives as long as a screen and doubled to take one more
3//! item would keep room for as many again.
4
5use std::hash::{BuildHasher, Hash};
6
7const MIN_TRIMMED_SLACK: usize = 16;
8
9fn slack_target(len: usize, capacity: usize) -> Option<usize> {
10    let slack = capacity.saturating_sub(len);
11    (slack > (len / 4).max(MIN_TRIMMED_SLACK)).then_some(len + len / 8)
12}
13
14/// A collection that can give back the room its growth left past its items.
15pub trait GrowthSlack {
16    /// Gives back the room past the items once it is more than a quarter of
17    /// them, and 16 at least, down to an eighth of them.
18    fn trim_growth_slack(&mut self);
19}
20
21impl<T> GrowthSlack for Vec<T> {
22    fn trim_growth_slack(&mut self) {
23        if let Some(target) = slack_target(self.len(), self.capacity()) {
24            self.shrink_to(target);
25        }
26    }
27}
28
29#[expect(
30    clippy::disallowed_types,
31    reason = "every hash map trims alike, whatever it hashes with"
32)]
33impl<K: Eq + Hash, V, S: BuildHasher> GrowthSlack for std::collections::HashMap<K, V, S> {
34    fn trim_growth_slack(&mut self) {
35        if let Some(target) = slack_target(self.len(), self.capacity()) {
36            self.shrink_to(target);
37        }
38    }
39}