diff --git a/phf/src/lib.rs b/phf/src/lib.rs index b8edb76b..4607c7ec 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -15,211 +15,20 @@ use core::fmt; use core::iter; use core::slice; use core::prelude::*; -use collections::{Map, Set}; +use collections::Map as MapTrait; +use collections::Set as SetTrait; pub use shared::PhfHash; +pub use map::Map; #[path="../../shared/mod.rs"] mod shared; +pub mod map; mod std { pub use core::fmt; } -/// An immutable map constructed at compile time. -/// -/// `PhfMap`s may be created with the `phf_map` macro: -/// -/// ```rust -/// # #![feature(phase)] -/// extern crate phf; -/// #[phase(plugin)] -/// extern crate phf_mac; -/// -/// use phf::PhfMap; -/// -/// static MY_MAP: PhfMap<&'static str, int> = phf_map! { -/// "hello" => 10, -/// "world" => 11, -/// }; -/// -/// # fn main() {} -/// ``` -/// -/// # Note -/// -/// The fields of this struct are public so that they may be initialized by the -/// `phf_map` macro. They are subject to change at any time and should never -/// be accessed directly. -pub struct PhfMap { - #[doc(hidden)] - pub key: u64, - #[doc(hidden)] - pub disps: &'static [(u32, u32)], - #[doc(hidden)] - pub entries: &'static [(K, V)], -} - -impl Collection for PhfMap { - fn len(&self) -> uint { - self.entries.len() - } -} - -impl<'a, K, V> Map for PhfMap where K: PhfHash+Eq { - fn find(&self, key: &K) -> Option<&V> { - self.get_entry(key, |k| key == k).map(|e| &e.1) - } -} - -impl fmt::Show for PhfMap where K: fmt::Show, V: fmt::Show { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - try!(write!(fmt, "{{")); - let mut first = true; - for &(ref k, ref v) in self.entries() { - if !first { - try!(write!(fmt, ", ")); - } - try!(write!(fmt, "{}: {}", k, v)) - first = false; - } - write!(fmt, "}}") - } -} - -impl Index for PhfMap where K: PhfHash+Eq { - fn index(&self, k: &K) -> &V { - self.find(k).expect("invalid key") - } -} - -impl PhfMap where K: PhfHash+Eq { - /// Returns a reference to the map's internal static instance of the given - /// key. - /// - /// This can be useful for interning schemes. - pub fn find_key(&self, key: &K) -> Option<&K> { - self.get_entry(key, |k| key == k).map(|e| &e.0) - } -} - -impl PhfMap { - fn get_entry(&self, key: &T, check: |&K| -> bool) -> Option<&(K, V)> where T: PhfHash { - let (g, f1, f2) = key.phf_hash(self.key); - let (d1, d2) = self.disps[(g % (self.disps.len() as u32)) as uint]; - let entry = &self.entries[(shared::displace(f1, f2, d1, d2) % (self.entries.len() as u32)) - as uint]; - if check(&entry.0) { - Some(entry) - } else { - None - } - } - - /// Like `find`, but can operate on any type that is equivalent to a key. - pub fn find_equiv(&self, key: &T) -> Option<&V> where T: PhfHash+Equiv { - self.get_entry(key, |k| key.equiv(k)).map(|e| &e.1) - } - - /// Like `find_key`, but can operate on any type that is equivalent to a - /// key. - pub fn find_key_equiv(&self, key: &T) -> Option<&K> where T: PhfHash+Equiv { - self.get_entry(key, |k| key.equiv(k)).map(|e| &e.0) - } -} - -impl PhfMap { - /// Returns an iterator over the key/value pairs in the map. - /// - /// Entries are retuned in an arbitrary but fixed order. - pub fn entries<'a>(&'a self) -> PhfMapEntries<'a, K, V> { - PhfMapEntries { iter: self.entries.iter() } - } - - /// Returns an iterator over the keys in the map. - /// - /// Keys are returned in an arbitrary but fixed order. - pub fn keys<'a>(&'a self) -> PhfMapKeys<'a, K, V> { - PhfMapKeys { iter: self.entries().map(|e| &e.0) } - } - - /// Returns an iterator over the values in the map. - /// - /// Values are returned in an arbitrary but fixed order. - pub fn values<'a>(&'a self) -> PhfMapValues<'a, K, V> { - PhfMapValues { iter: self.entries().map(|e | &e.1) } - } -} - -/// An iterator over the key/value pairs in a `PhfMap`. -pub struct PhfMapEntries<'a, K:'a, V:'a> { - iter: slice::Items<'a, (K, V)>, -} - -impl<'a, K, V> Iterator<&'a (K, V)> for PhfMapEntries<'a, K, V> { - fn next(&mut self) -> Option<&'a (K, V)> { - self.iter.next() - } - - fn size_hint(&self) -> (uint, Option) { - self.iter.size_hint() - } -} - -impl<'a, K, V> DoubleEndedIterator<&'a (K, V)> for PhfMapEntries<'a, K, V> { - fn next_back(&mut self) -> Option<&'a (K, V)> { - self.iter.next_back() - } -} - -impl<'a, K, V> ExactSize<&'a (K, V)> for PhfMapEntries<'a, K, V> {} - -/// An iterator over the keys in a `PhfMap`. -pub struct PhfMapKeys<'a, K:'a, V:'a> { - iter: iter::Map<'a, &'a (K, V), &'a K, PhfMapEntries<'a, K, V>>, -} - -impl<'a, K, V> Iterator<&'a K> for PhfMapKeys<'a, K, V> { - fn next(&mut self) -> Option<&'a K> { - self.iter.next() - } - - fn size_hint(&self) -> (uint, Option) { - self.iter.size_hint() - } -} - -impl<'a, K, V> DoubleEndedIterator<&'a K> for PhfMapKeys<'a, K, V> { - fn next_back(&mut self) -> Option<&'a K> { - self.iter.next_back() - } -} - -impl<'a, K, V> ExactSize<&'a K> for PhfMapKeys<'a, K, V> {} - -/// An iterator over the values in a `PhfMap`. -pub struct PhfMapValues<'a, K:'a, V:'a> { - iter: iter::Map<'a, &'a (K, V), &'a V, PhfMapEntries<'a, K, V>>, -} - -impl<'a, K, V> Iterator<&'a V> for PhfMapValues<'a, K, V> { - fn next(&mut self) -> Option<&'a V> { - self.iter.next() - } - - fn size_hint(&self) -> (uint, Option) { - self.iter.size_hint() - } -} - -impl<'a, K, V> DoubleEndedIterator<&'a V> for PhfMapValues<'a, K, V> { - fn next_back(&mut self) -> Option<&'a V> { - self.iter.next_back() - } -} - -impl<'a, K, V> ExactSize<&'a V> for PhfMapValues<'a, K, V> {} - /// An immutable set constructed at compile time. /// /// `PhfSet`s may be created with the `phf_set` macro: @@ -247,7 +56,7 @@ impl<'a, K, V> ExactSize<&'a V> for PhfMapValues<'a, K, V> {} /// accessed directly. pub struct PhfSet { #[doc(hidden)] - pub map: PhfMap + pub map: Map } impl fmt::Show for PhfSet where T: fmt::Show { @@ -272,7 +81,7 @@ impl Collection for PhfSet { } } -impl Set for PhfSet where T: PhfHash+Eq { +impl SetTrait for PhfSet where T: PhfHash+Eq { #[inline] fn contains(&self, value: &T) -> bool { self.map.contains_key(value) @@ -328,7 +137,7 @@ impl PhfSet { /// An iterator over the values in a `PhfSet`. pub struct PhfSetValues<'a, T:'static> { - iter: PhfMapKeys<'a, T, ()>, + iter: map::Keys<'a, T, ()>, } impl<'a, T> Iterator<&'a T> for PhfSetValues<'a, T> { @@ -409,7 +218,7 @@ impl Collection for PhfOrderedMap { } } -impl Map for PhfOrderedMap where K: PhfHash+Eq { +impl MapTrait for PhfOrderedMap where K: PhfHash+Eq { fn find(&self, key: &K) -> Option<&V> { self.find_entry(key, |k| k == key).map(|(_, e)| &e.1) } @@ -645,7 +454,7 @@ impl Collection for PhfOrderedSet { } } -impl Set for PhfOrderedSet where T: PhfHash+Eq { +impl SetTrait for PhfOrderedSet where T: PhfHash+Eq { #[inline] fn contains(&self, value: &T) -> bool { self.map.contains_key(value) diff --git a/phf/src/map.rs b/phf/src/map.rs new file mode 100644 index 00000000..88a5b1d5 --- /dev/null +++ b/phf/src/map.rs @@ -0,0 +1,204 @@ +//! An immutable map constructed at compile time. +use core::prelude::*; +use core::iter; +use core::slice; +use core::fmt; +use shared; +use collections::Map as MapTrait; +use shared::PhfHash; + +/// An immutable map constructed at compile time. +/// +/// `Map`s may be created with the `phf_map` macro: +/// +/// ```rust +/// # #![feature(phase)] +/// extern crate phf; +/// #[phase(plugin)] +/// extern crate phf_mac; +/// +/// use phf::Map; +/// +/// static MY_MAP: Map<&'static str, int> = phf_map! { +/// "hello" => 10, +/// "world" => 11, +/// }; +/// +/// # fn main() {} +/// ``` +/// +/// # Note +/// +/// The fields of this struct are public so that they may be initialized by the +/// `phf_map` macro. They are subject to change at any time and should never +/// be accessed directly. +pub struct Map { + #[doc(hidden)] + pub key: u64, + #[doc(hidden)] + pub disps: &'static [(u32, u32)], + #[doc(hidden)] + pub entries: &'static [(K, V)], +} + +impl Collection for Map { + fn len(&self) -> uint { + self.entries.len() + } +} + +impl<'a, K, V> MapTrait for Map where K: PhfHash+Eq { + fn find(&self, key: &K) -> Option<&V> { + self.get_entry(key, |k| key == k).map(|e| &e.1) + } +} + +impl fmt::Show for Map where K: fmt::Show, V: fmt::Show { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + try!(write!(fmt, "{{")); + let mut first = true; + for &(ref k, ref v) in self.entries() { + if !first { + try!(write!(fmt, ", ")); + } + try!(write!(fmt, "{}: {}", k, v)) + first = false; + } + write!(fmt, "}}") + } +} + +impl Index for Map where K: PhfHash+Eq { + fn index(&self, k: &K) -> &V { + self.find(k).expect("invalid key") + } +} + +impl Map where K: PhfHash+Eq { + /// Returns a reference to the map's internal static instance of the given + /// key. + /// + /// This can be useful for interning schemes. + pub fn find_key(&self, key: &K) -> Option<&K> { + self.get_entry(key, |k| key == k).map(|e| &e.0) + } +} + +impl Map { + fn get_entry(&self, key: &T, check: |&K| -> bool) -> Option<&(K, V)> where T: PhfHash { + let (g, f1, f2) = key.phf_hash(self.key); + let (d1, d2) = self.disps[(g % (self.disps.len() as u32)) as uint]; + let entry = &self.entries[(shared::displace(f1, f2, d1, d2) % (self.entries.len() as u32)) + as uint]; + if check(&entry.0) { + Some(entry) + } else { + None + } + } + + /// Like `find`, but can operate on any type that is equivalent to a key. + pub fn find_equiv(&self, key: &T) -> Option<&V> where T: PhfHash+Equiv { + self.get_entry(key, |k| key.equiv(k)).map(|e| &e.1) + } + + /// Like `find_key`, but can operate on any type that is equivalent to a + /// key. + pub fn find_key_equiv(&self, key: &T) -> Option<&K> where T: PhfHash+Equiv { + self.get_entry(key, |k| key.equiv(k)).map(|e| &e.0) + } +} + +impl Map { + /// Returns an iterator over the key/value pairs in the map. + /// + /// Entries are retuned in an arbitrary but fixed order. + pub fn entries<'a>(&'a self) -> Entries<'a, K, V> { + Entries { iter: self.entries.iter() } + } + + /// Returns an iterator over the keys in the map. + /// + /// Keys are returned in an arbitrary but fixed order. + pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { + Keys { iter: self.entries().map(|e| &e.0) } + } + + /// Returns an iterator over the values in the map. + /// + /// Values are returned in an arbitrary but fixed order. + pub fn values<'a>(&'a self) -> Values<'a, K, V> { + Values { iter: self.entries().map(|e | &e.1) } + } +} + +/// An iterator over the key/value pairs in a `Map`. +pub struct Entries<'a, K:'a, V:'a> { + iter: slice::Items<'a, (K, V)>, +} + +impl<'a, K, V> Iterator<&'a (K, V)> for Entries<'a, K, V> { + fn next(&mut self) -> Option<&'a (K, V)> { + self.iter.next() + } + + fn size_hint(&self) -> (uint, Option) { + self.iter.size_hint() + } +} + +impl<'a, K, V> DoubleEndedIterator<&'a (K, V)> for Entries<'a, K, V> { + fn next_back(&mut self) -> Option<&'a (K, V)> { + self.iter.next_back() + } +} + +impl<'a, K, V> ExactSize<&'a (K, V)> for Entries<'a, K, V> {} + +/// An iterator over the keys in a `Map`. +pub struct Keys<'a, K:'a, V:'a> { + iter: iter::Map<'a, &'a (K, V), &'a K, Entries<'a, K, V>>, +} + +impl<'a, K, V> Iterator<&'a K> for Keys<'a, K, V> { + fn next(&mut self) -> Option<&'a K> { + self.iter.next() + } + + fn size_hint(&self) -> (uint, Option) { + self.iter.size_hint() + } +} + +impl<'a, K, V> DoubleEndedIterator<&'a K> for Keys<'a, K, V> { + fn next_back(&mut self) -> Option<&'a K> { + self.iter.next_back() + } +} + +impl<'a, K, V> ExactSize<&'a K> for Keys<'a, K, V> {} + +/// An iterator over the values in a `Map`. +pub struct Values<'a, K:'a, V:'a> { + iter: iter::Map<'a, &'a (K, V), &'a V, Entries<'a, K, V>>, +} + +impl<'a, K, V> Iterator<&'a V> for Values<'a, K, V> { + fn next(&mut self) -> Option<&'a V> { + self.iter.next() + } + + fn size_hint(&self) -> (uint, Option) { + self.iter.size_hint() + } +} + +impl<'a, K, V> DoubleEndedIterator<&'a V> for Values<'a, K, V> { + fn next_back(&mut self) -> Option<&'a V> { + self.iter.next_back() + } +} + +impl<'a, K, V> ExactSize<&'a V> for Values<'a, K, V> {} + + diff --git a/phf/tests/test.rs b/phf/tests/test.rs index 71204252..924bec88 100644 --- a/phf/tests/test.rs +++ b/phf/tests/test.rs @@ -6,21 +6,21 @@ extern crate phf; mod map { use std::collections::{HashMap, HashSet}; - use phf::PhfMap; + use phf; #[allow(dead_code)] - static TRAILING_COMMA: PhfMap<&'static str, int> = phf_map!( + static TRAILING_COMMA: phf::Map<&'static str, int> = phf_map!( "foo" => 10, ); #[allow(dead_code)] - static NO_TRAILING_COMMA: PhfMap<&'static str, int> = phf_map!( + static NO_TRAILING_COMMA: phf::Map<&'static str, int> = phf_map!( "foo" => 10 ); #[test] fn test_two() { - static MAP: PhfMap<&'static str, int> = phf_map!( + static MAP: phf::Map<&'static str, int> = phf_map!( "foo" => 10, "bar" => 11, ); @@ -32,7 +32,7 @@ mod map { #[test] fn test_entries() { - static MAP: PhfMap<&'static str, int> = phf_map!( + static MAP: phf::Map<&'static str, int> = phf_map!( "foo" => 10, "bar" => 11, ); @@ -44,7 +44,7 @@ mod map { #[test] fn test_keys() { - static MAP: PhfMap<&'static str, int> = phf_map!( + static MAP: phf::Map<&'static str, int> = phf_map!( "foo" => 10, "bar" => 11, ); @@ -56,7 +56,7 @@ mod map { #[test] fn test_values() { - static MAP: PhfMap<&'static str, int> = phf_map!( + static MAP: phf::Map<&'static str, int> = phf_map!( "foo" => 10, "bar" => 11, ); @@ -68,7 +68,7 @@ mod map { #[test] fn test_large() { - static MAP: PhfMap<&'static str, int> = phf_map!( + static MAP: phf::Map<&'static str, int> = phf_map!( "a" => 0, "b" => 1, "c" => 2, @@ -101,7 +101,7 @@ mod map { #[test] fn test_macro_key() { - static MAP: PhfMap<&'static str, int> = phf_map!( + static MAP: phf::Map<&'static str, int> = phf_map!( concat!("foo", "bar") => 1 ); assert!(Some(&1) == MAP.find(&("foobar"))); @@ -109,7 +109,7 @@ mod map { #[test] fn test_non_static_str_key() { - static MAP: PhfMap<&'static str, int> = phf_map!( + static MAP: phf::Map<&'static str, int> = phf_map!( "a" => 0, ); assert_eq!(Some(&0), MAP.find_equiv("a".to_string()[])); @@ -117,7 +117,7 @@ mod map { #[test] fn test_index_ok() { - static MAP: PhfMap<&'static str, int> = phf_map!( + static MAP: phf::Map<&'static str, int> = phf_map!( "a" => 0, ); assert_eq!(0, MAP["a"]); @@ -126,7 +126,7 @@ mod map { #[test] #[should_fail] fn test_index_fail() { - static MAP: PhfMap<&'static str, int> = phf_map!( + static MAP: phf::Map<&'static str, int> = phf_map!( "a" => 0, ); MAP["b"]; @@ -134,7 +134,7 @@ mod map { macro_rules! test_key_type( ($t:ty, $($k:expr => $v:expr),+) => ({ - static MAP: PhfMap<$t, int> = phf_map! { + static MAP: phf::Map<$t, int> = phf_map! { $($k => $v),+ }; $( diff --git a/phf_mac/src/util.rs b/phf_mac/src/util.rs index a1224538..c7b053f0 100644 --- a/phf_mac/src/util.rs +++ b/phf_mac/src/util.rs @@ -210,7 +210,7 @@ pub fn create_map(cx: &mut ExtCtxt, sp: Span, entries: Vec, state: HashSt let entries = cx.expr_vec(sp, entries); let key = state.key; - MacExpr::new(quote_expr!(cx, ::phf::PhfMap { + MacExpr::new(quote_expr!(cx, ::phf::Map { key: $key, disps: &$disps, entries: &$entries,