Skip to content

Commit

Permalink
Future-proof specialization code
Browse files Browse the repository at this point in the history
  • Loading branch information
Amanieu committed Mar 17, 2020
1 parent eaaa366 commit b125106
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 30 deletions.
15 changes: 15 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,18 @@ macro_rules! cfg_if {
$(#[$m] $it)*
};
}

// Helper macro for specialization. This also helps avoid parse errors if the
// default fn syntax for specialization changes in the future.
#[cfg(feature = "nightly")]
macro_rules! default_fn {
($($tt:tt)*) => {
default $($tt)*
}
}
#[cfg(not(feature = "nightly"))]
macro_rules! default_fn {
($($tt:tt)*) => {
$($tt)*
}
}
44 changes: 23 additions & 21 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,32 +206,34 @@ impl<K: Clone, V: Clone, S: Clone> Clone for HashMap<K, V, S> {
// want the table to have elements hashed with the wrong hash_builder.
let hash_builder = source.hash_builder.clone();

#[cfg(not(feature = "nightly"))]
{
self.table.clone_from(&source.table);
}
#[cfg(feature = "nightly")]
{
trait HashClone<S> {
fn clone_from(&mut self, source: &Self, hash_builder: &S);
}
impl<K: Clone, V: Clone, S> HashClone<S> for HashMap<K, V, S> {
default fn clone_from(&mut self, source: &Self, _hash_builder: &S) {
// For backward-compatibility reasons we can't make the Clone impl
// depend on K: Hash + Eq and S: BuildHasher. However we can exploit
// this using specialization, which allows us to reuse the existing
// storage of the current HashMap to insert the cloned elements into.
trait HashClone<S> {
fn clone_from(&mut self, source: &Self, hash_builder: &S);
}
impl<K: Clone, V: Clone, S> HashClone<S> for HashMap<K, V, S> {
default_fn! {
#[cfg_attr(feature = "inline-more", inline)]
fn clone_from(&mut self, source: &Self, _hash_builder: &S) {
self.table.clone_from(&source.table);
}
}
impl<K: Clone, V: Clone, S> HashClone<S> for HashMap<K, V, S>
where
K: Eq + Hash,
S: BuildHasher,
{
fn clone_from(&mut self, source: &Self, hash_builder: &S) {
self.table
.clone_from_with_hasher(&source.table, |x| make_hash(hash_builder, &x.0));
}
}
#[cfg(feature = "nightly")]
impl<K: Clone, V: Clone, S> HashClone<S> for HashMap<K, V, S>
where
K: Eq + Hash,
S: BuildHasher,
{
#[cfg_attr(feature = "inline-more", inline)]
fn clone_from(&mut self, source: &Self, hash_builder: &S) {
self.table
.clone_from_with_hasher(&source.table, |x| make_hash(hash_builder, &x.0));
}
HashClone::clone_from(self, source, &hash_builder);
}
HashClone::clone_from(self, source, &hash_builder);

// Update hash_builder only if we successfully cloned all elements.
self.hash_builder = hash_builder;
Expand Down
13 changes: 4 additions & 9 deletions src/raw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1036,16 +1036,11 @@ trait RawTableClone {
unsafe fn clone_from_spec(&mut self, source: &Self, on_panic: impl FnMut(&mut Self));
}
impl<T: Clone> RawTableClone for RawTable<T> {
#[cfg(feature = "nightly")]
#[cfg_attr(feature = "inline-more", inline)]
default unsafe fn clone_from_spec(&mut self, source: &Self, on_panic: impl FnMut(&mut Self)) {
self.clone_from_impl(source, on_panic);
}

#[cfg(not(feature = "nightly"))]
#[cfg_attr(feature = "inline-more", inline)]
unsafe fn clone_from_spec(&mut self, source: &Self, on_panic: impl FnMut(&mut Self)) {
self.clone_from_impl(source, on_panic);
default_fn! {
unsafe fn clone_from_spec(&mut self, source: &Self, on_panic: impl FnMut(&mut Self)) {
self.clone_from_impl(source, on_panic);
}
}
}
#[cfg(feature = "nightly")]
Expand Down

0 comments on commit b125106

Please sign in to comment.