From 399ef081ecc36d2f165ff1f6debdcbf6a1dc7efb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 8 Jul 2023 13:34:23 -0700 Subject: [PATCH] Allow larger preallocated capacity for smaller elements --- serde/src/de/impls.rs | 19 ++++++++++--------- serde/src/private/de.rs | 13 ++++++++++--- serde/src/private/size_hint.rs | 14 +++++++++++--- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index 7cec26f60..12fbdfdb3 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -681,8 +681,8 @@ impl<'de> Visitor<'de> for CStringVisitor { where A: SeqAccess<'de>, { - let len = size_hint::cautious(seq.size_hint()); - let mut values = Vec::with_capacity(len); + let capacity = size_hint::cautious::(seq.size_hint()); + let mut values = Vec::::with_capacity(capacity); while let Some(value) = try!(seq.next_element()) { values.push(value); @@ -936,7 +936,7 @@ macro_rules! seq_impl { A: SeqAccess<'de>, { $clear(&mut self.0); - $reserve(&mut self.0, size_hint::cautious($access.size_hint())); + $reserve(&mut self.0, size_hint::cautious::($access.size_hint())); // FIXME: try to overwrite old values here? (Vec, VecDeque, LinkedList) while let Some(value) = try!($access.next_element()) { @@ -962,7 +962,7 @@ seq_impl!( BinaryHeap, seq, BinaryHeap::clear, - BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())), + BinaryHeap::with_capacity(size_hint::cautious::(seq.size_hint())), BinaryHeap::reserve, BinaryHeap::push ); @@ -992,7 +992,7 @@ seq_impl!( HashSet, seq, HashSet::clear, - HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()), + HashSet::with_capacity_and_hasher(size_hint::cautious::(seq.size_hint()), S::default()), HashSet::reserve, HashSet::insert ); @@ -1002,7 +1002,7 @@ seq_impl!( VecDeque, seq, VecDeque::clear, - VecDeque::with_capacity(size_hint::cautious(seq.size_hint())), + VecDeque::with_capacity(size_hint::cautious::(seq.size_hint())), VecDeque::reserve, VecDeque::push_back ); @@ -1036,7 +1036,8 @@ where where A: SeqAccess<'de>, { - let mut values = Vec::with_capacity(size_hint::cautious(seq.size_hint())); + let capacity = size_hint::cautious::(seq.size_hint()); + let mut values = Vec::::with_capacity(capacity); while let Some(value) = try!(seq.next_element()) { values.push(value); @@ -1072,7 +1073,7 @@ where where A: SeqAccess<'de>, { - let hint = size_hint::cautious(seq.size_hint()); + let hint = size_hint::cautious::(seq.size_hint()); if let Some(additional) = hint.checked_sub(self.0.len()) { self.0.reserve(additional); } @@ -1416,7 +1417,7 @@ map_impl!(BTreeMap, map, BTreeMap::new()); map_impl!( HashMap, map, - HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default()) + HashMap::with_capacity_and_hasher(size_hint::cautious::<(K, V)>(map.size_hint()), S::default()) ); //////////////////////////////////////////////////////////////////////////////// diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index 8eea2890c..51705d955 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -474,7 +474,8 @@ mod content { where V: SeqAccess<'de>, { - let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint())); + let mut vec = + Vec::::with_capacity(size_hint::cautious::(visitor.size_hint())); while let Some(e) = try!(visitor.next_element()) { vec.push(e); } @@ -485,7 +486,10 @@ mod content { where V: MapAccess<'de>, { - let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint())); + let mut vec = + Vec::<(Content, Content)>::with_capacity( + size_hint::cautious::<(Content, Content)>(visitor.size_hint()), + ); while let Some(kv) = try!(visitor.next_entry()) { vec.push(kv); } @@ -844,7 +848,10 @@ mod content { M: MapAccess<'de>, { let mut tag = None; - let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint())); + let mut vec = Vec::<(Content, Content)>::with_capacity(size_hint::cautious::<( + Content, + Content, + )>(map.size_hint())); while let Some(k) = try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) { match k { TagOrContent::Tag => { diff --git a/serde/src/private/size_hint.rs b/serde/src/private/size_hint.rs index ca71e616b..571af496a 100644 --- a/serde/src/private/size_hint.rs +++ b/serde/src/private/size_hint.rs @@ -8,9 +8,17 @@ where } #[cfg(any(feature = "std", feature = "alloc"))] -#[inline] -pub fn cautious(hint: Option) -> usize { - cmp::min(hint.unwrap_or(0), 4096) +pub fn cautious(hint: Option) -> usize { + const MAX_PREALLOC_BYTES: usize = 1024 * 1024; + + if mem::size_of::() == 0 { + 0 + } else { + cmp::min( + hint.unwrap_or(0), + MAX_PREALLOC_BYTES / mem::size_of::(), + ) + } } fn helper(bounds: (usize, Option)) -> Option {