X-Git-Url: https://git.chrismorgan.info/anymap/blobdiff_plain/6d0a64dcc97a1857f7e12be00189870860a68a3e..7866ca8d779805dc3a3134f2d247889a1721633c:/src/raw.rs diff --git a/src/raw.rs b/src/raw.rs index 445b137..0094b34 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -5,11 +5,12 @@ use std::any::TypeId; use std::borrow::Borrow; use std::collections::hash_map::{self, HashMap}; +use std::convert::TryInto; use std::hash::Hash; use std::hash::{Hasher, BuildHasherDefault}; +#[cfg(test)] use std::mem; use std::ops::{Index, IndexMut}; -use std::ptr; use any::{Any, UncheckedAnyExt}; @@ -19,19 +20,36 @@ struct TypeIdHasher { } impl Hasher for TypeIdHasher { - #[inline(always)] + #[inline] fn write(&mut self, bytes: &[u8]) { - // This expects to receive one and exactly one 64-bit value - debug_assert!(bytes.len() == 8); - unsafe { - ptr::copy_nonoverlapping(&mut self.value, mem::transmute(&bytes[0]), 1) - } + // This expects to receive exactly one 64-bit value, and there’s no realistic chance of + // that changing, but I don’t want to depend on something that isn’t expressly part of the + // contract for safety. But I’m OK with release builds putting everything in one bucket + // if it *did* change (and debug builds panicking). + debug_assert_eq!(bytes.len(), 8); + let _ = bytes.try_into() + .map(|array| self.value = u64::from_ne_bytes(array)); } - #[inline(always)] + #[inline] fn finish(&self) -> u64 { self.value } } +#[test] +fn type_id_hasher() { + fn verify_hashing_with(type_id: TypeId) { + let mut hasher = TypeIdHasher::default(); + type_id.hash(&mut hasher); + assert_eq!(hasher.finish(), unsafe { mem::transmute::(type_id) }); + } + // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c. + verify_hashing_with(TypeId::of::()); + verify_hashing_with(TypeId::of::<()>()); + verify_hashing_with(TypeId::of::()); + verify_hashing_with(TypeId::of::<&str>()); + verify_hashing_with(TypeId::of::>()); +} + /// The raw, underlying form of a `Map`. /// /// At its essence, this is a wrapper around `HashMap>`, with the portions that @@ -40,12 +58,13 @@ impl Hasher for TypeIdHasher { /// contents of an `Map`. However, because you will then be dealing with `Any` trait objects, it /// doesn’t tend to be so very useful. Still, if you need it, it’s here. #[derive(Debug)] -pub struct RawMap { +pub struct RawMap { inner: HashMap, BuildHasherDefault>, } // #[derive(Clone)] would want A to implement Clone, but in reality it’s only Box that can. impl Clone for RawMap where Box: Clone { + #[inline] fn clone(&self) -> RawMap { RawMap { inner: self.inner.clone(), @@ -53,19 +72,13 @@ impl Clone for RawMap where Box: Clone { } } -impl Default for RawMap { - fn default() -> RawMap { - RawMap::new() - } -} - impl_common_methods! { field: RawMap.inner; new() => HashMap::with_hasher(Default::default()); with_capacity(capacity) => HashMap::with_capacity_and_hasher(capacity, Default::default()); } -/// RawMap iterator. +/// `RawMap` iterator. #[derive(Clone)] pub struct Iter<'a, A: ?Sized + UncheckedAnyExt> { inner: hash_map::Iter<'a, TypeId, Box>, @@ -79,7 +92,7 @@ impl<'a, A: ?Sized + UncheckedAnyExt> ExactSizeIterator for Iter<'a, A> { #[inline] fn len(&self) -> usize { self.inner.len() } } -/// RawMap mutable iterator. +/// `RawMap` mutable iterator. pub struct IterMut<'a, A: ?Sized + UncheckedAnyExt> { inner: hash_map::IterMut<'a, TypeId, Box>, } @@ -92,7 +105,7 @@ impl<'a, A: ?Sized + UncheckedAnyExt> ExactSizeIterator for IterMut<'a, A> { #[inline] fn len(&self) -> usize { self.inner.len() } } -/// RawMap move iterator. +/// `RawMap` move iterator. pub struct IntoIter { inner: hash_map::IntoIter>, } @@ -105,18 +118,15 @@ impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { self.inner.len() } } -/// RawMap drain iterator. -#[cfg(feature = "unstable")] +/// `RawMap` drain iterator. pub struct Drain<'a, A: ?Sized + UncheckedAnyExt> { inner: hash_map::Drain<'a, TypeId, Box>, } -#[cfg(feature = "unstable")] impl<'a, A: ?Sized + UncheckedAnyExt> Iterator for Drain<'a, A> { type Item = Box; #[inline] fn next(&mut self) -> Option> { self.inner.next().map(|x| x.1) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } -#[cfg(feature = "unstable")] impl<'a, A: ?Sized + UncheckedAnyExt> ExactSizeIterator for Drain<'a, A> { #[inline] fn len(&self) -> usize { self.inner.len() } } @@ -148,7 +158,6 @@ impl RawMap { /// /// Keeps the allocated memory for reuse. #[inline] - #[cfg(feature = "unstable")] pub fn drain(&mut self) -> Drain { Drain { inner: self.inner.drain(), @@ -156,6 +165,7 @@ impl RawMap { } /// Gets the entry for the given type in the collection for in-place manipulation. + #[inline] pub fn entry(&mut self, key: TypeId) -> Entry { match self.inner.entry(key) { hash_map::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry { @@ -171,6 +181,7 @@ impl RawMap { /// /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. + #[inline] pub fn get(&self, k: &Q) -> Option<&A> where TypeId: Borrow, Q: Hash + Eq { self.inner.get(k).map(|x| &**x) @@ -180,6 +191,7 @@ impl RawMap { /// /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. + #[inline] pub fn contains_key(&self, k: &Q) -> bool where TypeId: Borrow, Q: Hash + Eq { self.inner.contains_key(k) @@ -189,6 +201,7 @@ impl RawMap { /// /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. + #[inline] pub fn get_mut(&mut self, k: &Q) -> Option<&mut A> where TypeId: Borrow, Q: Hash + Eq { self.inner.get_mut(k).map(|x| &mut **x) @@ -199,6 +212,7 @@ impl RawMap { /// /// It is the caller’s responsibility to ensure that the key corresponds with the type ID of /// the value. If they do not, memory safety may be violated. + #[inline] pub unsafe fn insert(&mut self, key: TypeId, value: Box) -> Option> { self.inner.insert(key, value) } @@ -208,6 +222,7 @@ impl RawMap { /// /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. + #[inline] pub fn remove(&mut self, k: &Q) -> Option> where TypeId: Borrow, Q: Hash + Eq { self.inner.remove(k) @@ -218,13 +233,15 @@ impl RawMap { impl Index for RawMap where TypeId: Borrow, Q: Eq + Hash { type Output = A; - fn index<'a>(&'a self, index: Q) -> &'a A { + #[inline] + fn index(&self, index: Q) -> &A { self.get(&index).expect("no entry found for key") } } impl IndexMut for RawMap where TypeId: Borrow, Q: Eq + Hash { - fn index_mut<'a>(&'a mut self, index: Q) -> &'a mut A { + #[inline] + fn index_mut(&mut self, index: Q) -> &mut A { self.get_mut(&index).expect("no entry found for key") } } @@ -233,6 +250,7 @@ impl IntoIterator for RawMap { type Item = Box; type IntoIter = IntoIter; + #[inline] fn into_iter(self) -> IntoIter { IntoIter { inner: self.inner.into_iter(), @@ -264,6 +282,7 @@ impl<'a, A: ?Sized + UncheckedAnyExt> Entry<'a, A> { /// /// It is the caller’s responsibility to ensure that the key of the entry corresponds with /// the type ID of `value`. If they do not, memory safety may be violated. + #[inline] pub unsafe fn or_insert(self, default: Box) -> &'a mut A { match self { Entry::Occupied(inner) => inner.into_mut(), @@ -276,6 +295,7 @@ impl<'a, A: ?Sized + UncheckedAnyExt> Entry<'a, A> { /// /// It is the caller’s responsibility to ensure that the key of the entry corresponds with /// the type ID of `value`. If they do not, memory safety may be violated. + #[inline] pub unsafe fn or_insert_with Box>(self, default: F) -> &'a mut A { match self { Entry::Occupied(inner) => inner.into_mut(), @@ -286,17 +306,20 @@ impl<'a, A: ?Sized + UncheckedAnyExt> Entry<'a, A> { impl<'a, A: ?Sized + UncheckedAnyExt> OccupiedEntry<'a, A> { /// Gets a reference to the value in the entry. + #[inline] pub fn get(&self) -> &A { &**self.inner.get() } /// Gets a mutable reference to the value in the entry. + #[inline] pub fn get_mut(&mut self) -> &mut A { &mut **self.inner.get_mut() } /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the collection itself. + #[inline] pub fn into_mut(self) -> &'a mut A { &mut **self.inner.into_mut() } @@ -305,11 +328,13 @@ impl<'a, A: ?Sized + UncheckedAnyExt> OccupiedEntry<'a, A> { /// /// It is the caller’s responsibility to ensure that the key of the entry corresponds with /// the type ID of `value`. If they do not, memory safety may be violated. + #[inline] pub unsafe fn insert(&mut self, value: Box) -> Box { self.inner.insert(value) } /// Takes the value out of the entry, and returns it. + #[inline] pub fn remove(self) -> Box { self.inner.remove() } @@ -321,6 +346,7 @@ impl<'a, A: ?Sized + UncheckedAnyExt> VacantEntry<'a, A> { /// /// It is the caller’s responsibility to ensure that the key of the entry corresponds with /// the type ID of `value`. If they do not, memory safety may be violated. + #[inline] pub unsafe fn insert(self, value: Box) -> &'a mut A { &mut **self.inner.insert(value) }