Commit 13ec8d5d by Abseil Team Committed by Copybara-Service

Add `absl::swap` functions for `*_hash_*` to avoid calling `std::swap`

We already have `swap(raw_hash_set&, raw_hash_set&)` thus we may expect argument dependent lookup will use that function in following code snippet:
```
absl::flat_hash_map<...> x, y;
using std::swap;
swap(x, y);
```
But in practice `std::swap` will be called because `swap(raw_hash_set&, raw_hash_set&)` requires derived-to-base conversion while `std::swap` doesn't (it is a function template), thus `std::swap` is picked by compiler.

To avoid this, we need a `swap` implementations which accept the exact `*_hash_*` types which is more preferred over `std::swap`.

Note that this will fix issues#1571.

PiperOrigin-RevId: 657419420
Change-Id: Id003b2129187ce2d4583029789ff96247d1490de
parent 52fad5aa
...@@ -573,6 +573,21 @@ typename flat_hash_map<K, V, H, E, A>::size_type erase_if( ...@@ -573,6 +573,21 @@ typename flat_hash_map<K, V, H, E, A>::size_type erase_if(
return container_internal::EraseIf(pred, &c); return container_internal::EraseIf(pred, &c);
} }
// swap(flat_hash_map<>, flat_hash_map<>)
//
// Swaps the contents of two `flat_hash_map` containers.
//
// NOTE: we need to define this function template in order for
// `flat_hash_set::swap` to be called instead of `std::swap`. Even though we
// have `swap(raw_hash_set&, raw_hash_set&)` defined, that function requires a
// derived-to-base conversion, whereas `std::swap` is a function template so
// `std::swap` will be preferred by compiler.
template <typename K, typename V, typename H, typename E, typename A>
void swap(flat_hash_map<K, V, H, E, A>& x,
flat_hash_map<K, V, H, E, A>& y) noexcept(noexcept(x.swap(y))) {
x.swap(y);
}
namespace container_internal { namespace container_internal {
// c_for_each_fast(flat_hash_map<>, Function) // c_for_each_fast(flat_hash_map<>, Function)
......
...@@ -477,6 +477,21 @@ typename flat_hash_set<T, H, E, A>::size_type erase_if( ...@@ -477,6 +477,21 @@ typename flat_hash_set<T, H, E, A>::size_type erase_if(
return container_internal::EraseIf(pred, &c); return container_internal::EraseIf(pred, &c);
} }
// swap(flat_hash_set<>, flat_hash_set<>)
//
// Swaps the contents of two `flat_hash_set` containers.
//
// NOTE: we need to define this function template in order for
// `flat_hash_set::swap` to be called instead of `std::swap`. Even though we
// have `swap(raw_hash_set&, raw_hash_set&)` defined, that function requires a
// derived-to-base conversion, whereas `std::swap` is a function template so
// `std::swap` will be preferred by compiler.
template <typename T, typename H, typename E, typename A>
void swap(flat_hash_set<T, H, E, A>& x,
flat_hash_set<T, H, E, A>& y) noexcept(noexcept(x.swap(y))) {
return x.swap(y);
}
namespace container_internal { namespace container_internal {
// c_for_each_fast(flat_hash_set<>, Function) // c_for_each_fast(flat_hash_set<>, Function)
......
...@@ -557,6 +557,21 @@ typename node_hash_map<K, V, H, E, A>::size_type erase_if( ...@@ -557,6 +557,21 @@ typename node_hash_map<K, V, H, E, A>::size_type erase_if(
return container_internal::EraseIf(pred, &c); return container_internal::EraseIf(pred, &c);
} }
// swap(node_hash_map<>, node_hash_map<>)
//
// Swaps the contents of two `node_hash_map` containers.
//
// NOTE: we need to define this function template in order for
// `flat_hash_set::swap` to be called instead of `std::swap`. Even though we
// have `swap(raw_hash_set&, raw_hash_set&)` defined, that function requires a
// derived-to-base conversion, whereas `std::swap` is a function template so
// `std::swap` will be preferred by compiler.
template <typename K, typename V, typename H, typename E, typename A>
void swap(node_hash_map<K, V, H, E, A>& x,
node_hash_map<K, V, H, E, A>& y) noexcept(noexcept(x.swap(y))) {
return x.swap(y);
}
namespace container_internal { namespace container_internal {
// c_for_each_fast(node_hash_map<>, Function) // c_for_each_fast(node_hash_map<>, Function)
......
...@@ -466,6 +466,21 @@ typename node_hash_set<T, H, E, A>::size_type erase_if( ...@@ -466,6 +466,21 @@ typename node_hash_set<T, H, E, A>::size_type erase_if(
return container_internal::EraseIf(pred, &c); return container_internal::EraseIf(pred, &c);
} }
// swap(node_hash_set<>, node_hash_set<>)
//
// Swaps the contents of two `node_hash_set` containers.
//
// NOTE: we need to define this function template in order for
// `flat_hash_set::swap` to be called instead of `std::swap`. Even though we
// have `swap(raw_hash_set&, raw_hash_set&)` defined, that function requires a
// derived-to-base conversion, whereas `std::swap` is a function template so
// `std::swap` will be preferred by compiler.
template <typename T, typename H, typename E, typename A>
void swap(node_hash_set<T, H, E, A>& x,
node_hash_set<T, H, E, A>& y) noexcept(noexcept(x.swap(y))) {
return x.swap(y);
}
namespace container_internal { namespace container_internal {
// c_for_each_fast(node_hash_set<>, Function) // c_for_each_fast(node_hash_set<>, Function)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment