mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-01 07:13:24 +03:00
Add complexity estimation of iterating over HashSet and HashMap
It is not obvious (at least for me) that complexity of iteration over hash tables depends on capacity and not length. Especially comparing with other containers like Vec or String. I think, this behaviour is worth mentioning. I run benchmark which tests iteration time for maps with length 50 and different capacities and get this results: ``` capacity - time 64 - 203.87 ns 256 - 351.78 ns 1024 - 607.87 ns 4096 - 965.82 ns 16384 - 3.1188 us ``` If you want to dig why it behaves such way, you can look current implementation in [hashbrown code](https://github.com/rust-lang/hashbrown/blob/f3a9f211d06f78c5beb81ac22ea08fdc269e068f/src/raw/mod.rs#L1933). Benchmarks code would be presented in PR related to this commit.
This commit is contained in:
@@ -344,6 +344,11 @@ pub fn capacity(&self) -> usize {
|
||||
/// println!("{key}");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, iterating over keys takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn keys(&self) -> Keys<'_, K, V> {
|
||||
Keys { inner: self.iter() }
|
||||
@@ -370,6 +375,11 @@ pub fn keys(&self) -> Keys<'_, K, V> {
|
||||
/// vec.sort_unstable();
|
||||
/// assert_eq!(vec, ["a", "b", "c"]);
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, iterating over keys takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[inline]
|
||||
#[rustc_lint_query_instability]
|
||||
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
|
||||
@@ -395,6 +405,11 @@ pub fn into_keys(self) -> IntoKeys<K, V> {
|
||||
/// println!("{val}");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, iterating over values takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn values(&self) -> Values<'_, K, V> {
|
||||
Values { inner: self.iter() }
|
||||
@@ -422,6 +437,11 @@ pub fn values(&self) -> Values<'_, K, V> {
|
||||
/// println!("{val}");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, iterating over values takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[stable(feature = "map_values_mut", since = "1.10.0")]
|
||||
pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
|
||||
ValuesMut { inner: self.iter_mut() }
|
||||
@@ -448,6 +468,11 @@ pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
|
||||
/// vec.sort_unstable();
|
||||
/// assert_eq!(vec, [1, 2, 3]);
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, iterating over values takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[inline]
|
||||
#[rustc_lint_query_instability]
|
||||
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
|
||||
@@ -473,6 +498,11 @@ pub fn into_values(self) -> IntoValues<K, V> {
|
||||
/// println!("key: {key} val: {val}");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, iterating over map takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[rustc_lint_query_instability]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn iter(&self) -> Iter<'_, K, V> {
|
||||
@@ -503,6 +533,11 @@ pub fn iter(&self) -> Iter<'_, K, V> {
|
||||
/// println!("key: {key} val: {val}");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, iterating over map takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[rustc_lint_query_instability]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
|
||||
@@ -633,6 +668,11 @@ pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
|
||||
/// map.retain(|&k, _| k % 2 == 0);
|
||||
/// assert_eq!(map.len(), 4);
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, this operation takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[inline]
|
||||
#[rustc_lint_query_instability]
|
||||
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
|
||||
|
||||
@@ -184,6 +184,11 @@ pub fn capacity(&self) -> usize {
|
||||
/// println!("{x}");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, iterating over set takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[inline]
|
||||
#[rustc_lint_query_instability]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@@ -312,6 +317,11 @@ pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
|
||||
/// set.retain(|&k| k % 2 == 0);
|
||||
/// assert_eq!(set.len(), 3);
|
||||
/// ```
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// In the current implementation, this operation takes O(capacity) time
|
||||
/// instead of O(len) because it internally visits empty buckets too.
|
||||
#[rustc_lint_query_instability]
|
||||
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
|
||||
pub fn retain<F>(&mut self, f: F)
|
||||
|
||||
Reference in New Issue
Block a user