X-Git-Url: https://git.chrismorgan.info/anymap/blobdiff_plain/6bd64ec0703e63441de187902de9f272c59f47cc..7dc36adf24d48394bcb9d0aa802746e3d4a1f564:/src/lib.rs diff --git a/src/lib.rs b/src/lib.rs index 2d03c56..0c71e36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,21 @@ //! This crate provides the `AnyMap` type, a safe and convenient store for one value of each type. -#![crate_id = "anymap#0.9"] -#![crate_type = "rlib"] -#![crate_type = "dylib"] +#![crate_name = "anymap"] +#![crate_type = "lib"] #![feature(default_type_params)] #![warn(unnecessary_qualification, non_uppercase_statics, variant_size_difference, managed_heap_memory, unnecessary_typecast, - missing_doc, unused_result, deprecated_owned_vector)] + missing_doc, unused_result)] #[cfg(test)] extern crate test; -use std::any::{Any, AnyRefExt, AnyMutRefExt}; +use std::any::Any; use std::intrinsics::TypeId; -use std::collections::HashMap; +use std::collections::{Collection, HashMap, Mutable}; use std::hash::{Hash, Hasher, Writer}; +use std::mem::{transmute, transmute_copy}; +use std::raw::TraitObject; struct TypeIdHasher; @@ -29,7 +30,7 @@ impl Writer for TypeIdState { debug_assert!(bytes.len() == 8); unsafe { std::ptr::copy_nonoverlapping_memory(&mut self.value, - std::mem::transmute(&bytes[0]), + transmute(&bytes[0]), 1) } } @@ -45,6 +46,42 @@ impl Hasher for TypeIdHasher { } } +/// An extension of `AnyRefExt` allowing unchecked downcasting of trait objects to `&T`. +trait UncheckedAnyRefExt<'a> { + /// Returns a reference to the boxed value, assuming that it is of type `T`. This should only be + /// called if you are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not. + unsafe fn as_ref_unchecked(self) -> &'a T; +} + +impl<'a> UncheckedAnyRefExt<'a> for &'a Any { + #[inline] + unsafe fn as_ref_unchecked(self) -> &'a T { + // Get the raw representation of the trait object + let to: TraitObject = transmute_copy(&self); + + // Extract the data pointer + transmute(to.data) + } +} + +/// An extension of `AnyMutRefExt` allowing unchecked downcasting of trait objects to `&mut T`. +trait UncheckedAnyMutRefExt<'a> { + /// Returns a reference to the boxed value, assuming that it is of type `T`. This should only be + /// called if you are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not. + unsafe fn as_mut_unchecked(self) -> &'a mut T; +} + +impl<'a> UncheckedAnyMutRefExt<'a> for &'a mut Any { + #[inline] + unsafe fn as_mut_unchecked(self) -> &'a mut T { + // Get the raw representation of the trait object + let to: TraitObject = transmute_copy(&self); + + // Extract the data pointer + transmute(to.data) + } +} + /// A map containing zero or one values for any given type and allowing convenient, /// type-safe access to those values. /// @@ -71,7 +108,7 @@ impl Hasher for TypeIdHasher { /// /// Values containing non-static references are not permitted. pub struct AnyMap { - data: HashMap:'static, TypeIdHasher>, + data: HashMap, TypeIdHasher>, } impl AnyMap { @@ -86,31 +123,54 @@ impl AnyMap { impl AnyMap { /// Retrieve the value stored in the map for the type `T`, if it exists. pub fn find<'a, T: 'static>(&'a self) -> Option<&'a T> { - self.data.find(&TypeId::of::()).and_then(|any| any.as_ref::()) + self.data.find(&TypeId::of::()).map(|any| unsafe { any.as_ref_unchecked::() }) } /// Retrieve a mutable reference to the value stored in the map for the type `T`, if it exists. pub fn find_mut<'a, T: 'static>(&'a mut self) -> Option<&'a mut T> { - self.data.find_mut(&TypeId::of::()).and_then(|any| any.as_mut::()) + self.data.find_mut(&TypeId::of::()).map(|any| unsafe { any.as_mut_unchecked::() }) } /// Set the value contained in the map for the type `T`. /// This will override any previous value stored. pub fn insert(&mut self, value: T) { - self.data.insert(TypeId::of::(), box value as Box:'static); + self.data.insert(TypeId::of::(), box value as Box); } /// Remove the value for the type `T` if it existed. pub fn remove(&mut self) { self.data.remove(&TypeId::of::()); } + + /// Does a value of type `T` exist? + pub fn contains(&self) -> bool { + self.data.contains_key(&TypeId::of::()) + } +} + +impl Collection for AnyMap { + fn len(&self) -> uint { + self.data.len() + } + + fn is_empty(&self) -> bool { + self.data.is_empty() + } +} + +impl Mutable for AnyMap { + fn clear(&mut self) { + self.data.clear(); + } } #[bench] fn bench_insertion(b: &mut ::test::Bencher) { b.iter(|| { let mut data = AnyMap::new(); - data.insert(42i); + for _ in range(0u, 100) { + data.insert(42i); + } }) } @@ -118,7 +178,9 @@ fn bench_insertion(b: &mut ::test::Bencher) { fn bench_find_missing(b: &mut ::test::Bencher) { b.iter(|| { let data = AnyMap::new(); - assert_eq!(data.find(), None::<&int>); + for _ in range(0u, 100) { + assert_eq!(data.find(), None::<&int>); + } }) } @@ -127,6 +189,9 @@ fn bench_find_present(b: &mut ::test::Bencher) { b.iter(|| { let mut data = AnyMap::new(); data.insert(42i); - assert_eq!(data.find(), Some(&42i)); + // These inner loops are a feeble attempt to drown the other factors. + for _ in range(0u, 100) { + assert_eq!(data.find(), Some(&42i)); + } }) }