Skip to content

Commit

Permalink
Build union of two maps/sets by mutating the larger one, not the first
Browse files Browse the repository at this point in the history
`fn union(self, other: Self) -> Self` is implemented by progressively
mutating then returning one of the two given collections,
while consuming and iterating the other.

If one of the two collections is much larger,
mutating that one can be faster and yield better reuse of internal nodes.
  • Loading branch information
SimonSapin authored and bodil committed Apr 29, 2022
1 parent 7c96460 commit ab09f18
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 18 deletions.
28 changes: 23 additions & 5 deletions src/hash/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,11 +932,16 @@ where
/// assert_eq!(expected, map1.union(map2));
/// ```
#[must_use]
pub fn union(mut self, other: Self) -> Self {
for (k, v) in other {
self.entry(k).or_insert(v);
pub fn union(self, other: Self) -> Self {
let (mut to_mutate, to_consume) = if self.len() >= other.len() {
(self, other)
} else {
(other, self)
};
for (k, v) in to_consume {
to_mutate.entry(k).or_insert(v);
}
self
to_mutate
}

/// Construct the union of two maps, using a function to decide
Expand Down Expand Up @@ -982,7 +987,20 @@ where
/// ));
/// ```
#[must_use]
pub fn union_with_key<F>(mut self, other: Self, mut f: F) -> Self
pub fn union_with_key<F>(self, other: Self, mut f: F) -> Self
where
F: FnMut(&K, V, V) -> V,
{
if self.len() >= other.len() {
self.union_with_key_inner(other, f)
} else {
other.union_with_key_inner(self, |key, other_value, self_value| {
f(key, self_value, other_value)
})
}
}

fn union_with_key_inner<F>(mut self, other: Self, mut f: F) -> Self
where
F: FnMut(&K, V, V) -> V,
{
Expand Down
13 changes: 9 additions & 4 deletions src/hash/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,11 +512,16 @@ where
/// assert_eq!(expected, set1.union(set2));
/// ```
#[must_use]
pub fn union(mut self, other: Self) -> Self {
for value in other {
self.insert(value);
pub fn union(self, other: Self) -> Self {
let (mut to_mutate, to_consume) = if self.len() >= other.len() {
(self, other)
} else {
(other, self)
};
for value in to_consume {
to_mutate.insert(value);
}
self
to_mutate
}

/// Construct the union of multiple sets.
Expand Down
28 changes: 23 additions & 5 deletions src/ord/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -981,11 +981,16 @@ where
/// ```
#[inline]
#[must_use]
pub fn union(mut self, other: Self) -> Self {
for (k, v) in other {
self.entry(k).or_insert(v);
pub fn union(self, other: Self) -> Self {
let (mut to_mutate, to_consume) = if self.len() >= other.len() {
(self, other)
} else {
(other, self)
};
for (k, v) in to_consume {
to_mutate.entry(k).or_insert(v);
}
self
to_mutate
}

/// Construct the union of two maps, using a function to decide
Expand Down Expand Up @@ -1031,7 +1036,20 @@ where
/// ));
/// ```
#[must_use]
pub fn union_with_key<F>(mut self, other: Self, mut f: F) -> Self
pub fn union_with_key<F>(self, other: Self, mut f: F) -> Self
where
F: FnMut(&K, V, V) -> V,
{
if self.len() >= other.len() {
self.union_with_key_inner(other, f)
} else {
other.union_with_key_inner(self, |key, other_value, self_value| {
f(key, self_value, other_value)
})
}
}

fn union_with_key_inner<F>(mut self, other: Self, mut f: F) -> Self
where
F: FnMut(&K, V, V) -> V,
{
Expand Down
13 changes: 9 additions & 4 deletions src/ord/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,11 +636,16 @@ where
/// assert_eq!(expected, set1.union(set2));
/// ```
#[must_use]
pub fn union(mut self, other: Self) -> Self {
for value in other {
self.insert(value);
pub fn union(self, other: Self) -> Self {
let (mut to_mutate, to_consume) = if self.len() >= other.len() {
(self, other)
} else {
(other, self)
};
for value in to_consume {
to_mutate.insert(value);
}
self
to_mutate
}

/// Construct the union of multiple sets.
Expand Down

0 comments on commit ab09f18

Please sign in to comment.