From 782694eb16f3c41378d9cc6166898cc4282db744 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Jun 2014 07:23:59 -0700 Subject: [PATCH 01/30] Add a cargo config --- .gitignore | 1 + Cargo.toml | 15 +++++++++++++++ phf_cargo_hack/Cargo.toml | 10 ++++++++++ 3 files changed, 26 insertions(+) create mode 100644 Cargo.toml create mode 100644 phf_cargo_hack/Cargo.toml diff --git a/.gitignore b/.gitignore index 0160015..042c112 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /build/ /doc/ /Makefile +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a0865c1 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] + +name = "phf_mac" +authors = ["Steven Fackler "] +version = "0.0.1" + +[[lib]] + +name = "phf_mac" +path = "src/phf_mac.rs" +crate_type = ["dylib"] + +[dependencies.phf] + +path = "phf_cargo_hack" diff --git a/phf_cargo_hack/Cargo.toml b/phf_cargo_hack/Cargo.toml new file mode 100644 index 0000000..f47c631 --- /dev/null +++ b/phf_cargo_hack/Cargo.toml @@ -0,0 +1,10 @@ +[package] + +name = "phf" +authors = ["Steven Fackler "] +version = "0.0.1" + +[[lib]] + +name = "phf" +path = "../src/phf.rs" From efc5c5602a4edb2c5b2e9a6178cda65e02e93c59 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 25 Jun 2014 22:10:39 -0700 Subject: [PATCH 02/30] Drop to version 0.0.0 --- Cargo.toml | 2 +- phf_cargo_hack/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a0865c1..041dc6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "phf_mac" authors = ["Steven Fackler "] -version = "0.0.1" +version = "0.0.0" [[lib]] diff --git a/phf_cargo_hack/Cargo.toml b/phf_cargo_hack/Cargo.toml index f47c631..b231f54 100644 --- a/phf_cargo_hack/Cargo.toml +++ b/phf_cargo_hack/Cargo.toml @@ -2,7 +2,7 @@ name = "phf" authors = ["Steven Fackler "] -version = "0.0.1" +version = "0.0.0" [[lib]] From 51680c03d69fa5baacba0b05708ea2b04f61edf7 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 27 Jun 2014 09:11:17 -0700 Subject: [PATCH 03/30] Fix type inference --- src/test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test.rs b/src/test.rs index d75869b..aeba168 100644 --- a/src/test.rs +++ b/src/test.rs @@ -189,7 +189,7 @@ mod ordered_map { "baz" => 12, ); let vec = MAP.entries().map(|(k, &v)| (k, v)).collect::>(); - assert_eq!(vec, vec!(("foo", 10), ("bar", 11), ("baz", 12))); + assert_eq!(vec, vec!(("foo", 10i), ("bar", 11), ("baz", 12))); } #[test] @@ -211,7 +211,7 @@ mod ordered_map { "baz" => 12, ); let vec = MAP.values().map(|&v| v).collect::>(); - assert_eq!(vec, vec!(10, 11, 12)); + assert_eq!(vec, vec!(10i, 11, 12)); } } From e11ed04b4be329f651c998a938ca9aa6ab14a909 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 29 Jun 2014 13:52:41 -0700 Subject: [PATCH 04/30] Switch docs back to rust-ci (again) --- .travis.yml | 6 +++++- src/phf.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34e77ea..baf2e17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ -install: +env: + global: + - secure: ffCiAwT3mkRQ57yTyTKUV4nRsnsdDuTSXbwSFpNg/AXLn6KTt35wpp2kbKTUhU4fUikpoKh30+TMiXp1vhc7XSUo/E06JyjccRIE6oXas07NcYhYd0JRlPPWKZU8q33jvFYFB7U63vY/65tGk+wlrWm7NFyqqXwGMuysd7XT1tE=install: - curl -O http://static.rust-lang.org/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz - tar xfz rust-nightly-x86_64-unknown-linux-gnu.tar.gz - (cd rust-nightly-x86_64-unknown-linux-gnu/ && sudo ./install.sh) @@ -6,3 +8,5 @@ before_script: - ./configure script: - make all check doc +after_script: + - curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh diff --git a/src/phf.rs b/src/phf.rs index 07a086b..0c23ad0 100644 --- a/src/phf.rs +++ b/src/phf.rs @@ -1,6 +1,6 @@ //! Compile time optimized maps #![crate_id="github.com/sfackler/rust-phf/phf"] -#![doc(html_root_url="http://sfackler.github.io/rust-phf/doc")] +#![doc(html_root_url="http://www.rust-ci.org/sfackler")] #![crate_type="rlib"] #![crate_type="dylib"] #![warn(missing_doc)] From 76d740dddfae265e633cb15a4af75e50d924f252 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 29 Jun 2014 13:54:36 -0700 Subject: [PATCH 05/30] Fix travis.yaml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index baf2e17..baf6dbf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ env: global: - - secure: ffCiAwT3mkRQ57yTyTKUV4nRsnsdDuTSXbwSFpNg/AXLn6KTt35wpp2kbKTUhU4fUikpoKh30+TMiXp1vhc7XSUo/E06JyjccRIE6oXas07NcYhYd0JRlPPWKZU8q33jvFYFB7U63vY/65tGk+wlrWm7NFyqqXwGMuysd7XT1tE=install: + - secure: ffCiAwT3mkRQ57yTyTKUV4nRsnsdDuTSXbwSFpNg/AXLn6KTt35wpp2kbKTUhU4fUikpoKh30+TMiXp1vhc7XSUo/E06JyjccRIE6oXas07NcYhYd0JRlPPWKZU8q33jvFYFB7U63vY/65tGk+wlrWm7NFyqqXwGMuysd7XT1tE= +install: - curl -O http://static.rust-lang.org/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz - tar xfz rust-nightly-x86_64-unknown-linux-gnu.tar.gz - (cd rust-nightly-x86_64-unknown-linux-gnu/ && sudo ./install.sh) From 424fde45ba7c9792276e1ce792a3cb744babb3d4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 29 Jun 2014 14:12:11 -0700 Subject: [PATCH 06/30] Fix doc link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37a2157..a64a927 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ It currently uses the [CHD algorithm](http://cmph.sourceforge.net/papers/esa09.pdf) and can generate a 10,000 entry map in roughly .25 seconds. -Documentation is available at http://sfackler.github.io/rust-phf/doc/phf/index.html. +Documentation is available at http://www.rust-ci.org/sfackler/rust-phf/doc/phf/. Example ======= From 4ff35445a4b376009d0f365bd761c2c27c174c4c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 2 Jul 2014 20:25:43 -0700 Subject: [PATCH 07/30] Split to two separate Cargo packages --- .gitignore | 3 ++- Makefile.in | 6 +++--- {phf_cargo_hack => phf}/Cargo.toml | 2 +- src/phf.rs => phf/src/lib.rs | 0 {src => phf/src}/test.rs | 0 Cargo.toml => phf_mac/Cargo.toml | 4 ++-- src/phf_mac.rs => phf_mac/src/lib.rs | 0 7 files changed, 8 insertions(+), 7 deletions(-) rename {phf_cargo_hack => phf}/Cargo.toml (83%) rename src/phf.rs => phf/src/lib.rs (100%) rename {src => phf/src}/test.rs (100%) rename Cargo.toml => phf_mac/Cargo.toml (77%) rename src/phf_mac.rs => phf_mac/src/lib.rs (100%) diff --git a/.gitignore b/.gitignore index 042c112..b71287e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /build/ /doc/ /Makefile -/target +/phf/target/ +/phf_mac/target/ diff --git a/Makefile.in b/Makefile.in index da04a16..ab4f0bb 100644 --- a/Makefile.in +++ b/Makefile.in @@ -3,11 +3,11 @@ BUILDDIR := build RUSTFLAGS := -O --cfg ndebug INSTALL_DIR := %PREFIX% -PHF_LIB := src/phf.rs +PHF_LIB := phf/src/lib.rs PHF := $(foreach file,$(shell $(RUSTC) --crate-file-name $(PHF_LIB)),$(BUILDDIR)/$(file)) -PHF_MAC_LIB := src/phf_mac.rs +PHF_MAC_LIB := phf_mac/src/lib.rs PHF_MAC := $(BUILDDIR)/$(shell $(RUSTC) --crate-file-name $(PHF_MAC_LIB)) -PHF_TEST_MAIN := src/test.rs +PHF_TEST_MAIN := phf/src/test.rs PHF_TEST := $(BUILDDIR)/$(shell $(RUSTC) --crate-file-name $(PHF_TEST_MAIN)) all: $(PHF) $(PHF_MAC) diff --git a/phf_cargo_hack/Cargo.toml b/phf/Cargo.toml similarity index 83% rename from phf_cargo_hack/Cargo.toml rename to phf/Cargo.toml index b231f54..b0249b8 100644 --- a/phf_cargo_hack/Cargo.toml +++ b/phf/Cargo.toml @@ -7,4 +7,4 @@ version = "0.0.0" [[lib]] name = "phf" -path = "../src/phf.rs" +path = "src/lib.rs" diff --git a/src/phf.rs b/phf/src/lib.rs similarity index 100% rename from src/phf.rs rename to phf/src/lib.rs diff --git a/src/test.rs b/phf/src/test.rs similarity index 100% rename from src/test.rs rename to phf/src/test.rs diff --git a/Cargo.toml b/phf_mac/Cargo.toml similarity index 77% rename from Cargo.toml rename to phf_mac/Cargo.toml index 041dc6f..00f56a9 100644 --- a/Cargo.toml +++ b/phf_mac/Cargo.toml @@ -7,9 +7,9 @@ version = "0.0.0" [[lib]] name = "phf_mac" -path = "src/phf_mac.rs" +path = "src/lib.rs" crate_type = ["dylib"] [dependencies.phf] -path = "phf_cargo_hack" +path = "../phf" diff --git a/src/phf_mac.rs b/phf_mac/src/lib.rs similarity index 100% rename from src/phf_mac.rs rename to phf_mac/src/lib.rs From 473131ff05b5ea215a3fa336e1c89687a764b727 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 5 Jul 2014 10:09:42 -0700 Subject: [PATCH 08/30] Fix for upstream changes --- phf_mac/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index 54b1ee4..12a36ab 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -361,8 +361,8 @@ fn create_map(cx: &mut ExtCtxt, sp: Span, entries: Vec, state: HashState) MacExpr::new(quote_expr!(cx, ::phf::PhfMap { k1: $k1, k2: $k2, - disps: &'static $disps, - entries: &'static $entries, + disps: &$disps, + entries: &$entries, })) } @@ -392,9 +392,9 @@ fn create_ordered_map(cx: &mut ExtCtxt, sp: Span, entries: Vec, MacExpr::new(quote_expr!(cx, ::phf::PhfOrderedMap { k1: $k1, k2: $k2, - disps: &'static $disps, - idxs: &'static $idxs, - entries: &'static $entries, + disps: &$disps, + idxs: &$idxs, + entries: &$entries, })) } From a0ab8d7f517305c77cdb1d51076ff4b3e31923e5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 7 Jul 2014 09:19:48 -0700 Subject: [PATCH 09/30] Update for crate_id removal --- Makefile.in | 6 +++--- phf/src/lib.rs | 2 +- phf_mac/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.in b/Makefile.in index ab4f0bb..d67ab03 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,11 +4,11 @@ RUSTFLAGS := -O --cfg ndebug INSTALL_DIR := %PREFIX% PHF_LIB := phf/src/lib.rs -PHF := $(foreach file,$(shell $(RUSTC) --crate-file-name $(PHF_LIB)),$(BUILDDIR)/$(file)) +PHF := $(foreach file,$(shell $(RUSTC) --print-file-name $(PHF_LIB)),$(BUILDDIR)/$(file)) PHF_MAC_LIB := phf_mac/src/lib.rs -PHF_MAC := $(BUILDDIR)/$(shell $(RUSTC) --crate-file-name $(PHF_MAC_LIB)) +PHF_MAC := $(BUILDDIR)/$(shell $(RUSTC) --print-file-name $(PHF_MAC_LIB)) PHF_TEST_MAIN := phf/src/test.rs -PHF_TEST := $(BUILDDIR)/$(shell $(RUSTC) --crate-file-name $(PHF_TEST_MAIN)) +PHF_TEST := $(BUILDDIR)/$(shell $(RUSTC) --print-file-name $(PHF_TEST_MAIN)) all: $(PHF) $(PHF_MAC) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index 0c23ad0..173377e 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -1,5 +1,5 @@ //! Compile time optimized maps -#![crate_id="github.com/sfackler/rust-phf/phf"] +#![crate_name="phf"] #![doc(html_root_url="http://www.rust-ci.org/sfackler")] #![crate_type="rlib"] #![crate_type="dylib"] diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index 12a36ab..a3f0c6e 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -1,7 +1,7 @@ //! Compiler plugin for Rust-PHF //! //! See the documentation for the `phf` crate for more details. -#![crate_id="github.com/sfackler/rust-phf/phf_mac"] +#![crate_name="phf_mac"] #![crate_type="dylib"] #![doc(html_root_url="http://sfackler.github.io/rust-phf/doc")] #![feature(plugin_registrar, quote)] From cb4ed93175b656f442802c27e039add8e2b86723 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Jul 2014 20:19:08 -0700 Subject: [PATCH 10/30] Parameterize the key type of PhfMap and Set We don't actually support anything beyond &'static str right now, but this will allow other keys in the future. --- phf/src/lib.rs | 184 ++++++++++++++++++++++++++------------------- phf/src/test.rs | 49 ++++++------ phf_mac/src/lib.rs | 2 +- 3 files changed, 132 insertions(+), 103 deletions(-) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index 173377e..ae1e8c5 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -6,11 +6,33 @@ #![warn(missing_doc)] use std::fmt; -use std::hash::Hasher; +use std::hash::{Hash, Hasher}; use std::hash::sip::SipHasher; use std::slice; use std::collections::Collection; +static LOG_MAX_SIZE: uint = 21; + +#[doc(hidden)] +pub static MAX_SIZE: uint = 1 << LOG_MAX_SIZE; + +#[doc(hidden)] +#[inline] +pub fn hash(s: &T, k1: u64, k2: u64) -> (uint, uint, uint) { + let hash = SipHasher::new_with_keys(k1, k2).hash(s); + let mask = (MAX_SIZE - 1) as u64; + + ((hash & mask) as uint, + ((hash >> LOG_MAX_SIZE) & mask) as uint, + ((hash >> (2 * LOG_MAX_SIZE)) & mask) as uint) +} + +#[doc(hidden)] +#[inline] +pub fn displace(f1: uint, f2: uint, d1: uint, d2: uint) -> uint { + d2 + f1 * d1 + f2 +} + /// An immutable map constructed at compile time. /// /// `PhfMap`s may be created with the `phf_map` macro: @@ -23,7 +45,7 @@ use std::collections::Collection; /// /// use phf::PhfMap; /// -/// static MY_MAP: PhfMap = phf_map! { +/// static MY_MAP: PhfMap<&'static str, int> = phf_map! { /// "hello" => 10, /// "world" => 11, /// }; @@ -36,7 +58,7 @@ use std::collections::Collection; /// 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 { +pub struct PhfMap { #[doc(hidden)] pub k1: u64, #[doc(hidden)] @@ -44,48 +66,29 @@ pub struct PhfMap { #[doc(hidden)] pub disps: &'static [(uint, uint)], #[doc(hidden)] - pub entries: &'static [(&'static str, T)], -} - -static LOG_MAX_SIZE: uint = 21; - -#[doc(hidden)] -pub static MAX_SIZE: uint = 1 << LOG_MAX_SIZE; - -#[doc(hidden)] -#[inline] -pub fn hash(s: &str, k1: u64, k2: u64) -> (uint, uint, uint) { - let hash = SipHasher::new_with_keys(k1, k2).hash(&s); - let mask = (MAX_SIZE - 1) as u64; - - ((hash & mask) as uint, - ((hash >> LOG_MAX_SIZE) & mask) as uint, - ((hash >> (2 * LOG_MAX_SIZE)) & mask) as uint) + pub entries: &'static [(K, V)], } -#[doc(hidden)] -#[inline] -pub fn displace(f1: uint, f2: uint, d1: uint, d2: uint) -> uint { - d2 + f1 * d1 + f2 -} - -impl Collection for PhfMap { +impl Collection for PhfMap { fn len(&self) -> uint { self.entries.len() } } -impl<'a, T> Map<&'a str, T> for PhfMap { - fn find<'a>(&'a self, key: & &str) -> Option<&'a T> { - self.find_entry(key).map(|&(_, ref v)| v) +impl<'a, K: Hash+Eq, V> Map for PhfMap { + fn find<'a>(&'a self, key: &K) -> Option<&'a V> { + self.get_entry(key, |k| key == k).map(|e| { + let &(_, ref v) = e; + v + }) } } -impl fmt::Show for PhfMap { +impl fmt::Show for PhfMap { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "{{")); let mut first = true; - for (k, v) in self.entries() { + for &(ref k, ref v) in self.entries() { if !first { try!(write!(fmt, ", ")); } @@ -96,13 +99,14 @@ impl fmt::Show for PhfMap { } } -impl PhfMap { - fn find_entry(&self, key: & &str) -> Option<&'static (&'static str, T)> { - let (g, f1, f2) = hash(*key, self.k1, self.k2); +impl PhfMap { + fn get_entry<'a, T: Hash>(&'a self, key: &T, check: |&K| -> bool) + -> Option<&'a (K, V)> { + let (g, f1, f2) = hash(key, self.k1, self.k2); let (d1, d2) = self.disps[g % self.disps.len()]; - let entry @ &(s, _) = &self.entries[displace(f1, f2, d1, d2) % - self.entries.len()]; - if s == *key { + let entry @ &(ref s, _) = &self.entries[displace(f1, f2, d1, d2) % + self.entries.len()]; + if check(s) { Some(entry) } else { None @@ -113,40 +117,64 @@ impl PhfMap { /// key. /// /// This can be useful for interning schemes. - pub fn find_key(&self, key: & &str) -> Option<&'static str> { - self.find_entry(key).map(|&(s, _)| s) + pub fn find_key<'a>(&'a self, key: &K) -> Option<&'a K> { + self.get_entry(key, |k| key == k).map(|e| { + let &(ref k, _) = e; + k + }) + } + + /// Like `find`, but can operate on any type that is equivalent to a key. + pub fn find_equiv<'a, T: Hash+Equiv>(&'a self, key: &T) + -> Option<&'a V> { + self.get_entry(key, |k| key.equiv(k)).map(|e| { + let &(_, ref v) = e; + v + }) + } + + /// Like `find_key`, but can operate on any type that is equivalent to a + /// key. + pub fn find_key_equiv<'a, T: Hash+Equiv>(&'a self, key: &T) + -> Option<&'a K> { + self.get_entry(key, |k| key.equiv(k)).map(|e| { + let &(ref k, _) = e; + k + }) } +} +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, T> { + 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, T> { + pub fn keys<'a>(&'a self) -> PhfMapKeys<'a, K, V> { PhfMapKeys { iter: self.entries() } } /// 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, T> { + pub fn values<'a>(&'a self) -> PhfMapValues<'a, K, V> { PhfMapValues { iter: self.entries() } } } /// An iterator over the key/value pairs in a `PhfMap`. -pub struct PhfMapEntries<'a, T> { - iter: slice::Items<'a, (&'static str, T)>, +pub struct PhfMapEntries<'a, K, V> { + iter: slice::Items<'a, (K, V)>, } -impl<'a, T> Iterator<(&'static str, &'a T)> for PhfMapEntries<'a, T> { - fn next(&mut self) -> Option<(&'static str, &'a T)> { - self.iter.next().map(|&(key, ref value)| (key, value)) +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) { @@ -155,13 +183,13 @@ impl<'a, T> Iterator<(&'static str, &'a T)> for PhfMapEntries<'a, T> { } /// An iterator over the keys in a `PhfMap`. -pub struct PhfMapKeys<'a, T> { - iter: PhfMapEntries<'a, T>, +pub struct PhfMapKeys<'a, K, V> { + iter: PhfMapEntries<'a, K, V>, } -impl<'a, T> Iterator<&'static str> for PhfMapKeys<'a, T> { - fn next(&mut self) -> Option<&'static str> { - self.iter.next().map(|(key, _)| key) +impl<'a, K, V> Iterator<&'a K> for PhfMapKeys<'a, K, V> { + fn next(&mut self) -> Option<&'a K> { + self.iter.next().map(|&(ref key, _)| key) } fn size_hint(&self) -> (uint, Option) { @@ -170,13 +198,13 @@ impl<'a, T> Iterator<&'static str> for PhfMapKeys<'a, T> { } /// An iterator over the values in a `PhfMap`. -pub struct PhfMapValues<'a, T> { - iter: PhfMapEntries<'a, T>, +pub struct PhfMapValues<'a, K, V> { + iter: PhfMapEntries<'a, K, V>, } -impl<'a, T> Iterator<&'a T> for PhfMapValues<'a, T> { - fn next(&mut self) -> Option<&'a T> { - self.iter.next().map(|(_, value)| value) +impl<'a, K, V> Iterator<&'a V> for PhfMapValues<'a, K, V> { + fn next(&mut self) -> Option<&'a V> { + self.iter.next().map(|&(_, ref value)| value) } fn size_hint(&self) -> (uint, Option) { @@ -196,7 +224,7 @@ impl<'a, T> Iterator<&'a T> for PhfMapValues<'a, T> { /// /// use phf::PhfSet; /// -/// static MY_SET: PhfSet = phf_set! { +/// static MY_SET: PhfSet<&'static str> = phf_set! { /// "hello", /// "world", /// }; @@ -209,12 +237,12 @@ impl<'a, T> Iterator<&'a T> for PhfMapValues<'a, T> { /// The fields of this struct are public so that they may be initialized by the /// `phf_set` macro. They are subject to change at any time and should never be /// accessed directly. -pub struct PhfSet { +pub struct PhfSet { #[doc(hidden)] - pub map: PhfMap<()> + pub map: PhfMap } -impl fmt::Show for PhfSet { +impl fmt::Show for PhfSet { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "{{")); let mut first = true; @@ -229,57 +257,59 @@ impl fmt::Show for PhfSet { } } -impl Collection for PhfSet { +impl Collection for PhfSet { #[inline] fn len(&self) -> uint { self.map.len() } } -impl<'a> Set<&'a str> for PhfSet { +impl<'a, T: Hash+Eq> Set for PhfSet { #[inline] - fn contains(&self, value: & &'a str) -> bool { + fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } #[inline] - fn is_disjoint(&self, other: &PhfSet) -> bool { - !self.iter().any(|value| other.contains(&value)) + fn is_disjoint(&self, other: &PhfSet) -> bool { + !self.iter().any(|value| other.contains(value)) } #[inline] - fn is_subset(&self, other: &PhfSet) -> bool { - self.iter().all(|value| other.contains(&value)) + fn is_subset(&self, other: &PhfSet) -> bool { + self.iter().all(|value| other.contains(value)) } } -impl PhfSet { +impl PhfSet { /// Returns a reference to the set's internal static instance of the given /// key. /// /// This can be useful for interning schemes. #[inline] - pub fn find_key(&self, key: & &str) -> Option<&'static str> { + pub fn find_key<'a>(&'a self, key: &T) -> Option<&'a T> { self.map.find_key(key) } +} +impl PhfSet { /// Returns an iterator over the values in the set. /// /// Values are returned in an arbitrary but fixed order. #[inline] - pub fn iter<'a>(&'a self) -> PhfSetValues<'a> { + pub fn iter<'a>(&'a self) -> PhfSetValues<'a, T> { PhfSetValues { iter: self.map.keys() } } } /// An iterator over the values in a `PhfSet`. -pub struct PhfSetValues<'a> { - iter: PhfMapKeys<'a, ()>, +pub struct PhfSetValues<'a, T> { + iter: PhfMapKeys<'a, T, ()>, } -impl<'a> Iterator<&'static str> for PhfSetValues<'a> { +impl<'a, T> Iterator<&'a T> for PhfSetValues<'a, T> { #[inline] - fn next(&mut self) -> Option<&'static str> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } @@ -359,7 +389,7 @@ impl<'a, T> Map<&'a str, T> for PhfOrderedMap { impl PhfOrderedMap { fn find_entry(&self, key: & &str) -> Option<&'static (&'static str, T)> { - let (g, f1, f2) = hash(*key, self.k1, self.k2); + let (g, f1, f2) = hash(key, self.k1, self.k2); let (d1, d2) = self.disps[g % self.disps.len()]; let idx = self.idxs[displace(f1, f2, d1, d2) % self.idxs.len()]; let entry @ &(s, _) = &self.entries[idx]; diff --git a/phf/src/test.rs b/phf/src/test.rs index aeba168..2a948ee 100644 --- a/phf/src/test.rs +++ b/phf/src/test.rs @@ -9,18 +9,18 @@ mod map { use phf::PhfMap; #[allow(dead_code)] - static TRAILING_COMMA: PhfMap = phf_map!( + static TRAILING_COMMA: PhfMap<&'static str, int> = phf_map!( "foo" => 10, ); #[allow(dead_code)] - static NO_TRAILING_COMMA: PhfMap = phf_map!( + static NO_TRAILING_COMMA: PhfMap<&'static str, int> = phf_map!( "foo" => 10 ); #[test] fn test_two() { - static map: PhfMap = phf_map!( + static map: PhfMap<&'static str, int> = phf_map!( "foo" => 10, "bar" => 11, ); @@ -32,14 +32,11 @@ mod map { #[test] fn test_entries() { - static map: PhfMap = phf_map!( + static map: PhfMap<&'static str, int> = phf_map!( "foo" => 10, "bar" => 11, ); - let mut hash = HashMap::new(); - for (key, &value) in map.entries() { - hash.insert(key, value); - } + let hash = map.entries().map(|&e| e).collect::>(); assert!(Some(&10) == hash.find(&("foo"))); assert!(Some(&11) == hash.find(&("bar"))); assert_eq!(2, hash.len()); @@ -47,14 +44,11 @@ mod map { #[test] fn test_keys() { - static map: PhfMap = phf_map!( + static map: PhfMap<&'static str, int> = phf_map!( "foo" => 10, "bar" => 11, ); - let mut hash = HashSet::new(); - for key in map.keys() { - hash.insert(key); - } + let hash = map.keys().map(|&e| e).collect::>(); assert!(hash.contains(&("foo"))); assert!(hash.contains(&("bar"))); assert_eq!(2, hash.len()); @@ -62,14 +56,11 @@ mod map { #[test] fn test_values() { - static map: PhfMap = phf_map!( + static map: PhfMap<&'static str, int> = phf_map!( "foo" => 10, "bar" => 11, ); - let mut hash = HashSet::new(); - for &value in map.values() { - hash.insert(value); - } + let hash = map.values().map(|&e| e).collect::>(); assert!(hash.contains(&10)); assert!(hash.contains(&11)); assert_eq!(2, hash.len()); @@ -77,7 +68,7 @@ mod map { #[test] fn test_large() { - static map: PhfMap = phf_map!( + static map: PhfMap<&'static str, int> = phf_map!( "a" => 0, "b" => 1, "c" => 2, @@ -110,11 +101,19 @@ mod map { #[test] fn test_macro_key() { - static map: PhfMap = phf_map!( + static map: PhfMap<&'static str, int> = phf_map!( concat!("foo", "bar") => 1 ); assert!(Some(&1) == map.find(&("foobar"))); } + + #[test] + fn test_non_static_str_key() { + static map: PhfMap<&'static str, int> = phf_map!( + "a" => 0, + ); + assert_eq!(Some(&0), map.find_equiv(&"a".to_string().as_slice())); + } } mod set { @@ -122,18 +121,18 @@ mod set { use phf::PhfSet; #[allow(dead_code)] - static TRAILING_COMMA: PhfSet = phf_set! { + static TRAILING_COMMA: PhfSet<&'static str> = phf_set! { "foo", }; #[allow(dead_code)] - static NO_TRAILING_COMMA: PhfSet = phf_set! { + static NO_TRAILING_COMMA: PhfSet<&'static str> = phf_set! { "foo" }; #[test] fn test_two() { - static SET: PhfSet = phf_set! { + static SET: PhfSet<&'static str> = phf_set! { "hello", "world", }; @@ -145,11 +144,11 @@ mod set { #[test] fn test_iter() { - static SET: PhfSet = phf_set! { + static SET: PhfSet<&'static str> = phf_set! { "hello", "world", }; - let set = SET.iter().collect::>(); + let set = SET.iter().map(|e| *e).collect::>(); assert!(set.contains(&"hello")); assert!(set.contains(&"world")); assert_eq!(2, set.len()); diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index a3f0c6e..d24ba32 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -284,7 +284,7 @@ fn try_generate_hash(entries: &[Entry], rng: &mut XorShiftRng) let k2 = rng.gen(); let hashes: Vec = entries.iter().map(|entry| { - let (g, f1, f2) = phf::hash(entry.key_str.get(), k1, k2); + let (g, f1, f2) = phf::hash(&entry.key_str.get(), k1, k2); Hashes { g: g, f1: f1, From f6ce641e5676be8d70e961f020d79fc3d6dcfb74 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Jul 2014 21:20:53 -0700 Subject: [PATCH 11/30] Parameterize the key type of PhfOrdered* --- phf/src/lib.rs | 172 +++++++++++++++++++++++++----------------------- phf/src/test.rs | 26 ++++---- 2 files changed, 102 insertions(+), 96 deletions(-) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index ae1e8c5..9070f10 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -334,7 +334,7 @@ impl<'a, T> Iterator<&'a T> for PhfSetValues<'a, T> { /// /// use phf::PhfOrderedMap; /// -/// static MY_MAP: PhfOrderedMap = phf_ordered_map! { +/// static MY_MAP: PhfOrderedMap<&'static str, int> = phf_ordered_map! { /// "hello" => 10, /// "world" => 11, /// }; @@ -347,7 +347,7 @@ impl<'a, T> Iterator<&'a T> for PhfSetValues<'a, T> { /// The fields of this struct are public so that they may be initialized by the /// `phf_ordered_map` macro. They are subject to change at any time and should /// never be accessed directly. -pub struct PhfOrderedMap { +pub struct PhfOrderedMap { #[doc(hidden)] pub k1: u64, #[doc(hidden)] @@ -357,14 +357,14 @@ pub struct PhfOrderedMap { #[doc(hidden)] pub idxs: &'static [uint], #[doc(hidden)] - pub entries: &'static [(&'static str, T)], + pub entries: &'static [(K, V)], } -impl fmt::Show for PhfOrderedMap { +impl fmt::Show for PhfOrderedMap { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "{{")); let mut first = true; - for (k, v) in self.entries() { + for &(ref k, ref v) in self.entries() { if !first { try!(write!(fmt, ", ")); } @@ -375,26 +375,29 @@ impl fmt::Show for PhfOrderedMap { } } -impl Collection for PhfOrderedMap { +impl Collection for PhfOrderedMap { fn len(&self) -> uint { self.entries.len() } } -impl<'a, T> Map<&'a str, T> for PhfOrderedMap { - fn find<'a>(&'a self, key: & &str) -> Option<&'a T> { - self.find_entry(key).map(|&(_, ref v)| v) +impl<'a, K: Hash+Eq, V> Map for PhfOrderedMap { + fn find<'a>(&'a self, key: &K) -> Option<&'a V> { + self.find_entry(key).map(|e| { + let &(_, ref v) = e; + v + }) } } -impl PhfOrderedMap { - fn find_entry(&self, key: & &str) -> Option<&'static (&'static str, T)> { +impl PhfOrderedMap { + fn find_entry<'a>(&'a self, key: &K) -> Option<&'a (K, V)> { let (g, f1, f2) = hash(key, self.k1, self.k2); let (d1, d2) = self.disps[g % self.disps.len()]; let idx = self.idxs[displace(f1, f2, d1, d2) % self.idxs.len()]; - let entry @ &(s, _) = &self.entries[idx]; + let entry @ &(ref s, _) = &self.entries[idx]; - if s == *key { + if s == key { Some(entry) } else { None @@ -405,40 +408,45 @@ impl PhfOrderedMap { /// key. /// /// This can be useful for interning schemes. - pub fn find_key(&self, key: & &str) -> Option<&'static str> { - self.find_entry(key).map(|&(s, _)| s) + pub fn find_key<'a>(&'a self, key: &K) -> Option<&'a K> { + self.find_entry(key).map(|e| { + let &(ref k, _) = e; + k + }) } +} +impl PhfOrderedMap { /// Returns an iterator over the key/value pairs in the map. /// /// Entries are retuned in the same order in which they were defined. - pub fn entries<'a>(&'a self) -> PhfOrderedMapEntries<'a, T> { + pub fn entries<'a>(&'a self) -> PhfOrderedMapEntries<'a, K, V> { PhfOrderedMapEntries { iter: self.entries.iter() } } /// Returns an iterator over the keys in the map. /// /// Keys are returned in the same order in which they were defined. - pub fn keys<'a>(&'a self) -> PhfOrderedMapKeys<'a, T> { + pub fn keys<'a>(&'a self) -> PhfOrderedMapKeys<'a, K, V> { PhfOrderedMapKeys { iter: self.entries() } } /// Returns an iterator over the values in the map. /// /// Values are returned in the same order in which they were defined. - pub fn values<'a>(&'a self) -> PhfOrderedMapValues<'a, T> { + pub fn values<'a>(&'a self) -> PhfOrderedMapValues<'a, K, V> { PhfOrderedMapValues { iter: self.entries() } } } /// An iterator over the entries in a `PhfOrderedMap`. -pub struct PhfOrderedMapEntries<'a, T> { - iter: slice::Items<'a, (&'static str, T)>, +pub struct PhfOrderedMapEntries<'a, K, V> { + iter: slice::Items<'a, (K, V)>, } -impl<'a, T> Iterator<(&'static str, &'a T)> for PhfOrderedMapEntries<'a, T> { - fn next(&mut self) -> Option<(&'static str, &'a T)> { - self.iter.next().map(|&(key, ref value)| (key, value)) +impl<'a, K, V> Iterator<&'a (K, V)> for PhfOrderedMapEntries<'a, K, V> { + fn next(&mut self) -> Option<&'a (K, V)> { + self.iter.next() } fn size_hint(&self) -> (uint, Option) { @@ -446,38 +454,34 @@ impl<'a, T> Iterator<(&'static str, &'a T)> for PhfOrderedMapEntries<'a, T> { } } -impl<'a, T> DoubleEndedIterator<(&'static str, &'a T)> - for PhfOrderedMapEntries<'a, T> { - fn next_back(&mut self) -> Option<(&'static str, &'a T)> { - self.iter.next_back().map(|&(key, ref value)| (key, value)) +impl<'a, K, V> DoubleEndedIterator<&'a (K, V)> + for PhfOrderedMapEntries<'a, K, V> { + fn next_back(&mut self) -> Option<&'a (K, V)> { + self.iter.next_back() } } -impl<'a, T> RandomAccessIterator<(&'static str, &'a T)> - for PhfOrderedMapEntries<'a, T> { +impl<'a, K, V> RandomAccessIterator<&'a (K, V)> + for PhfOrderedMapEntries<'a, K, V> { fn indexable(&self) -> uint { self.iter.indexable() } - fn idx(&mut self, index: uint) -> Option<(&'static str, &'a T)> { - // FIXME: mozilla/rust#13167 - self.iter.idx(index).map(|pair| { - let &(key, ref value) = pair; - (key, value) - }) + fn idx(&mut self, index: uint) -> Option<&'a (K, V)> { + self.iter.idx(index) } } -impl<'a, T> ExactSize<(&'static str, &'a T)> for PhfOrderedMapEntries<'a, T> {} +impl<'a, K, V> ExactSize<&'a (K, V)> for PhfOrderedMapEntries<'a, K, V> {} /// An iterator over the keys in a `PhfOrderedMap`. -pub struct PhfOrderedMapKeys<'a, T> { - iter: PhfOrderedMapEntries<'a, T>, +pub struct PhfOrderedMapKeys<'a, K, V> { + iter: PhfOrderedMapEntries<'a, K, V>, } -impl<'a, T> Iterator<&'static str> for PhfOrderedMapKeys<'a, T> { - fn next(&mut self) -> Option<&'static str> { - self.iter.next().map(|(key, _)| key) +impl<'a, K, V> Iterator<&'a K> for PhfOrderedMapKeys<'a, K, V> { + fn next(&mut self) -> Option<&'a K> { + self.iter.next().map(|&(ref key, _)| key) } fn size_hint(&self) -> (uint, Option) { @@ -485,32 +489,32 @@ impl<'a, T> Iterator<&'static str> for PhfOrderedMapKeys<'a, T> { } } -impl<'a, T> DoubleEndedIterator<&'static str> for PhfOrderedMapKeys<'a, T> { - fn next_back(&mut self) -> Option<&'static str> { - self.iter.next_back().map(|(key, _)| key) +impl<'a, K, V> DoubleEndedIterator<&'a K> for PhfOrderedMapKeys<'a, K, V> { + fn next_back(&mut self) -> Option<&'a K> { + self.iter.next_back().map(|&(ref key, _)| key) } } -impl<'a, T> RandomAccessIterator<&'static str> for PhfOrderedMapKeys<'a, T> { +impl<'a, K, V> RandomAccessIterator<&'a K> for PhfOrderedMapKeys<'a, K, V> { fn indexable(&self) -> uint { self.iter.indexable() } - fn idx(&mut self, index: uint) -> Option<&'static str> { - self.iter.idx(index).map(|(key, _)| key) + fn idx(&mut self, index: uint) -> Option<&'a K> { + self.iter.idx(index).map(|&(ref key, _)| key) } } -impl<'a, T> ExactSize<&'static str> for PhfOrderedMapKeys<'a, T> {} +impl<'a, K, V> ExactSize<&'a K> for PhfOrderedMapKeys<'a, K, V> {} /// An iterator over the values in a `PhfOrderedMap`. -pub struct PhfOrderedMapValues<'a, T> { - iter: PhfOrderedMapEntries<'a, T>, +pub struct PhfOrderedMapValues<'a, K, V> { + iter: PhfOrderedMapEntries<'a, K, V>, } -impl<'a, T> Iterator<&'a T> for PhfOrderedMapValues<'a, T> { - fn next(&mut self) -> Option<&'a T> { - self.iter.next().map(|(_, value)| value) +impl<'a, K, V> Iterator<&'a V> for PhfOrderedMapValues<'a, K, V> { + fn next(&mut self) -> Option<&'a V> { + self.iter.next().map(|&(_, ref value)| value) } fn size_hint(&self) -> (uint, Option) { @@ -518,23 +522,23 @@ impl<'a, T> Iterator<&'a T> for PhfOrderedMapValues<'a, T> { } } -impl<'a, T> DoubleEndedIterator<&'a T> for PhfOrderedMapValues<'a, T> { - fn next_back(&mut self) -> Option<&'a T> { - self.iter.next_back().map(|(_, value)| value) +impl<'a, K, V> DoubleEndedIterator<&'a V> for PhfOrderedMapValues<'a, K, V> { + fn next_back(&mut self) -> Option<&'a V> { + self.iter.next_back().map(|&(_, ref value)| value) } } -impl<'a, T> RandomAccessIterator<&'a T> for PhfOrderedMapValues<'a, T> { +impl<'a, K, V> RandomAccessIterator<&'a V> for PhfOrderedMapValues<'a, K, V> { fn indexable(&self) -> uint { self.iter.indexable() } - fn idx(&mut self, index: uint) -> Option<&'a T> { - self.iter.idx(index).map(|(_, value)| value) + fn idx(&mut self, index: uint) -> Option<&'a V> { + self.iter.idx(index).map(|&(_, ref value)| value) } } -impl<'a, T> ExactSize<&'a T> for PhfOrderedMapValues<'a, T> {} +impl<'a, K, V> ExactSize<&'a V> for PhfOrderedMapValues<'a, K, V> {} /// An order-preserving immutable set constructed at compile time. /// @@ -551,7 +555,7 @@ impl<'a, T> ExactSize<&'a T> for PhfOrderedMapValues<'a, T> {} /// /// use phf::PhfOrderedSet; /// -/// static MY_SET: PhfOrderedSet = phf_ordered_set! { +/// static MY_SET: PhfOrderedSet<&'static str> = phf_ordered_set! { /// "hello", /// "world", /// }; @@ -564,12 +568,12 @@ impl<'a, T> ExactSize<&'a T> for PhfOrderedMapValues<'a, T> {} /// The fields of this struct are public so that they may be initialized by the /// `phf_ordered_set` macro. They are subject to change at any time and should /// never be accessed directly. -pub struct PhfOrderedSet { +pub struct PhfOrderedSet { #[doc(hidden)] - pub map: PhfOrderedMap<()>, + pub map: PhfOrderedMap, } -impl fmt::Show for PhfOrderedSet { +impl fmt::Show for PhfOrderedSet { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "{{")); let mut first = true; @@ -584,57 +588,59 @@ impl fmt::Show for PhfOrderedSet { } } -impl Collection for PhfOrderedSet { +impl Collection for PhfOrderedSet { #[inline] fn len(&self) -> uint { self.map.len() } } -impl<'a> Set<&'a str> for PhfOrderedSet { +impl Set for PhfOrderedSet { #[inline] - fn contains(&self, value: & &'a str) -> bool { + fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } #[inline] - fn is_disjoint(&self, other: &PhfOrderedSet) -> bool { - !self.iter().any(|value| other.contains(&value)) + fn is_disjoint(&self, other: &PhfOrderedSet) -> bool { + !self.iter().any(|value| other.contains(value)) } #[inline] - fn is_subset(&self, other: &PhfOrderedSet) -> bool { - self.iter().all(|value| other.contains(&value)) + fn is_subset(&self, other: &PhfOrderedSet) -> bool { + self.iter().all(|value| other.contains(value)) } } -impl PhfOrderedSet { +impl PhfOrderedSet { /// Returns a reference to the set's internal static instance of the given /// key. /// /// This can be useful for interning schemes. #[inline] - pub fn find_key(&self, key: & &str) -> Option<&'static str> { + pub fn find_key<'a>(&'a self, key: &T) -> Option<&'a T> { self.map.find_key(key) } +} +impl PhfOrderedSet { /// Returns an iterator over the values in the set. /// /// Values are returned in the same order in which they were defined. #[inline] - pub fn iter<'a>(&'a self) -> PhfOrderedSetValues<'a> { + pub fn iter<'a>(&'a self) -> PhfOrderedSetValues<'a, T> { PhfOrderedSetValues { iter: self.map.keys() } } } /// An iterator over the values in a `PhfOrderedSet`. -pub struct PhfOrderedSetValues<'a> { - iter: PhfOrderedMapKeys<'a, ()>, +pub struct PhfOrderedSetValues<'a, T> { + iter: PhfOrderedMapKeys<'a, T, ()>, } -impl<'a> Iterator<&'static str> for PhfOrderedSetValues<'a> { +impl<'a, T> Iterator<&'a T> for PhfOrderedSetValues<'a, T> { #[inline] - fn next(&mut self) -> Option<&'static str> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } @@ -644,23 +650,23 @@ impl<'a> Iterator<&'static str> for PhfOrderedSetValues<'a> { } } -impl<'a> DoubleEndedIterator<&'static str> for PhfOrderedSetValues<'a> { +impl<'a, T> DoubleEndedIterator<&'a T> for PhfOrderedSetValues<'a, T> { #[inline] - fn next_back(&mut self) -> Option<&'static str> { + fn next_back(&mut self) -> Option<&'a T> { self.iter.next_back() } } -impl<'a> RandomAccessIterator<&'static str> for PhfOrderedSetValues<'a> { +impl<'a, T> RandomAccessIterator<&'a T> for PhfOrderedSetValues<'a, T> { #[inline] fn indexable(&self) -> uint { self.iter.indexable() } #[inline] - fn idx(&mut self, index: uint) -> Option<&'static str> { + fn idx(&mut self, index: uint) -> Option<&'a T> { self.iter.idx(index) } } -impl<'a> ExactSize<&'static str> for PhfOrderedSetValues<'a> {} +impl<'a, T> ExactSize<&'a T> for PhfOrderedSetValues<'a, T> {} diff --git a/phf/src/test.rs b/phf/src/test.rs index 2a948ee..ef7ee04 100644 --- a/phf/src/test.rs +++ b/phf/src/test.rs @@ -159,18 +159,18 @@ mod ordered_map { use phf::PhfOrderedMap; #[allow(dead_code)] - static TRAILING_COMMA: PhfOrderedMap = phf_ordered_map!( + static TRAILING_COMMA: PhfOrderedMap<&'static str, int> = phf_ordered_map!( "foo" => 10, ); #[allow(dead_code)] - static NO_TRAILING_COMMA: PhfOrderedMap = phf_ordered_map!( + static NO_TRAILING_COMMA: PhfOrderedMap<&'static str, int> = phf_ordered_map!( "foo" => 10 ); #[test] fn test_two() { - static map: PhfOrderedMap = phf_ordered_map!( + static map: PhfOrderedMap<&'static str, int> = phf_ordered_map!( "foo" => 10, "bar" => 11, ); @@ -182,29 +182,29 @@ mod ordered_map { #[test] fn test_entries() { - static MAP: PhfOrderedMap = phf_ordered_map!( + static MAP: PhfOrderedMap<&'static str, int> = phf_ordered_map!( "foo" => 10, "bar" => 11, "baz" => 12, ); - let vec = MAP.entries().map(|(k, &v)| (k, v)).collect::>(); + let vec = MAP.entries().map(|&(k, v)| (k, v)).collect::>(); assert_eq!(vec, vec!(("foo", 10i), ("bar", 11), ("baz", 12))); } #[test] fn test_keys() { - static MAP: PhfOrderedMap = phf_ordered_map!( + static MAP: PhfOrderedMap<&'static str, int> = phf_ordered_map!( "foo" => 10, "bar" => 11, "baz" => 12, ); - let vec = MAP.keys().collect::>(); + let vec = MAP.keys().map(|&e| e).collect::>(); assert_eq!(vec, vec!("foo", "bar", "baz")); } #[test] fn test_values() { - static MAP: PhfOrderedMap = phf_ordered_map!( + static MAP: PhfOrderedMap<&'static str, int> = phf_ordered_map!( "foo" => 10, "bar" => 11, "baz" => 12, @@ -218,18 +218,18 @@ mod ordered_set { use phf::PhfOrderedSet; #[allow(dead_code)] - static TRAILING_COMMA: PhfOrderedSet = phf_ordered_set! { + static TRAILING_COMMA: PhfOrderedSet<&'static str> = phf_ordered_set! { "foo", }; #[allow(dead_code)] - static NO_TRAILING_COMMA: PhfOrderedSet = phf_ordered_set! { + static NO_TRAILING_COMMA: PhfOrderedSet<&'static str> = phf_ordered_set! { "foo" }; #[test] fn test_two() { - static SET: PhfOrderedSet = phf_ordered_set! { + static SET: PhfOrderedSet<&'static str> = phf_ordered_set! { "hello", "there", "world", @@ -243,12 +243,12 @@ mod ordered_set { #[test] fn test_iter() { - static SET: PhfOrderedSet = phf_ordered_set! { + static SET: PhfOrderedSet<&'static str> = phf_ordered_set! { "hello", "there", "world", }; - let vec = SET.iter().collect::>(); + let vec = SET.iter().map(|&e| e).collect::>(); assert_eq!(vec, vec!("hello", "there", "world")); } } From 04b11a12e7c59a088e7c0a5acb8da67b8951ca84 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Jul 2014 21:43:56 -0700 Subject: [PATCH 12/30] Plugin infrastructure for non-str keys --- phf_mac/src/lib.rs | 48 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index d24ba32..f4b9198 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -4,7 +4,7 @@ #![crate_name="phf_mac"] #![crate_type="dylib"] #![doc(html_root_url="http://sfackler.github.io/rust-phf/doc")] -#![feature(plugin_registrar, quote)] +#![feature(plugin_registrar, quote, default_type_params)] extern crate rand; extern crate syntax; @@ -13,7 +13,10 @@ extern crate phf; extern crate rustc; use std::collections::HashMap; +use std::fmt; use std::gc::{Gc, GC}; +use std::hash; +use std::hash::{Hash}; use std::os; use syntax::ast; use syntax::ast::{TokenTree, LitStr, Expr, ExprVec, ExprLit}; @@ -40,8 +43,29 @@ pub fn macro_registrar(reg: &mut Registry) { reg.register_macro("phf_ordered_set", expand_phf_ordered_set); } +#[deriving(PartialEq, Eq, Clone)] +enum Key { + StaticStr(InternedString), +} + +impl Hash for Key { + fn hash(&self, state: &mut S) { + match *self { + StaticStr(ref s) => s.get().hash(state), + } + } +} + +impl fmt::Show for Key { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + StaticStr(ref s) => s.fmt(fmt), + } + } +} + struct Entry { - key_str: InternedString, + key_contents: Key, key: Gc, value: Gc } @@ -125,9 +149,9 @@ fn parse_map(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { let mut bad = false; while parser.token != EOF { let key = cx.expand_expr(parser.parse_expr()); - let key_str = parse_str(cx, key).unwrap_or_else(|| { + let key_contents = parse_key(cx, key).unwrap_or_else(|| { bad = true; - InternedString::new("") + StaticStr(InternedString::new("")) }); if !parser.eat(&FAT_ARROW) { @@ -138,7 +162,7 @@ fn parse_map(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { let value = parser.parse_expr(); entries.push(Entry { - key_str: key_str, + key_contents: key_contents, key: key, value: value }); @@ -172,13 +196,13 @@ fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { let mut bad = false; while parser.token != EOF { let key = cx.expand_expr(parser.parse_expr()); - let key_str = parse_str(cx, key).unwrap_or_else(|| { + let key_contents = parse_key(cx, key).unwrap_or_else(|| { bad = true; - InternedString::new("") + StaticStr(InternedString::new("")) }); entries.push(Entry { - key_str: key_str, + key_contents: key_contents, key: key, value: value, }); @@ -203,11 +227,11 @@ fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { Some(entries) } -fn parse_str(cx: &mut ExtCtxt, e: &Expr) -> Option { +fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option { match e.node { ExprLit(lit) => { match lit.node { - LitStr(ref s, _) => Some(s.clone()), + LitStr(ref s, _) => Some(StaticStr(s.clone())), _ => { cx.span_err(e.span, "expected string literal"); None @@ -225,7 +249,7 @@ fn has_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool { let mut dups = false; let mut strings = HashMap::new(); for entry in entries.iter() { - let spans = strings.find_or_insert(entry.key_str.clone(), vec![]); + let spans = strings.find_or_insert(entry.key_contents.clone(), vec![]); spans.push(entry.key.span); } @@ -284,7 +308,7 @@ fn try_generate_hash(entries: &[Entry], rng: &mut XorShiftRng) let k2 = rng.gen(); let hashes: Vec = entries.iter().map(|entry| { - let (g, f1, f2) = phf::hash(&entry.key_str.get(), k1, k2); + let (g, f1, f2) = phf::hash(&entry.key_contents, k1, k2); Hashes { g: g, f1: f1, From 6bfb12bf3b0bffb66e44b8a5326051b58d697543 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Jul 2014 22:13:25 -0700 Subject: [PATCH 13/30] Support binary literal keys! --- phf/src/lib.rs | 8 ++++++++ phf/src/test.rs | 10 ++++++++++ phf_mac/src/lib.rs | 39 ++++++++++++++++++--------------------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index 9070f10..f8b8459 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -35,6 +35,8 @@ pub fn displace(f1: uint, f2: uint, d1: uint, d2: uint) -> uint { /// An immutable map constructed at compile time. /// +/// Keys may be either string literals or binary string literals. +/// /// `PhfMap`s may be created with the `phf_map` macro: /// /// ```rust @@ -214,6 +216,8 @@ impl<'a, K, V> Iterator<&'a V> for PhfMapValues<'a, K, V> { /// An immutable set constructed at compile time. /// +/// Values may be either string literals or binary string literals. +/// /// `PhfSet`s may be created with the `phf_set` macro: /// /// ```rust @@ -321,6 +325,8 @@ impl<'a, T> Iterator<&'a T> for PhfSetValues<'a, T> { /// An order-preserving immutable map constructed at compile time. /// +/// Keys may be either string literals or binary string literals. +/// /// Unlike a `PhfMap`, the order of entries in a `PhfOrderedMap` is guaranteed /// to be the order the entries were listed in. /// @@ -542,6 +548,8 @@ impl<'a, K, V> ExactSize<&'a V> for PhfOrderedMapValues<'a, K, V> {} /// An order-preserving immutable set constructed at compile time. /// +/// Values may be either string literals or binary string literals. +/// /// Unlike a `PhfSet`, the order of entries in a `PhfOrderedSet` is guaranteed /// to be the order the entries were listed in. /// diff --git a/phf/src/test.rs b/phf/src/test.rs index ef7ee04..b59c5d4 100644 --- a/phf/src/test.rs +++ b/phf/src/test.rs @@ -114,6 +114,16 @@ mod map { ); assert_eq!(Some(&0), map.find_equiv(&"a".to_string().as_slice())); } + + #[test] + fn test_binary_keys() { + static map: PhfMap<&'static [u8], int> = phf_map! { + b"hello" => 0, + b"world" => 1 + }; + assert_eq!(Some(&0), map.find(&b"hello")); + assert_eq!(Some(&1), map.find(&b"world")); + } } mod set { diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index f4b9198..40153f5 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -13,13 +13,13 @@ extern crate phf; extern crate rustc; use std::collections::HashMap; -use std::fmt; use std::gc::{Gc, GC}; use std::hash; use std::hash::{Hash}; use std::os; +use std::rc::Rc; use syntax::ast; -use syntax::ast::{TokenTree, LitStr, Expr, ExprVec, ExprLit}; +use syntax::ast::{TokenTree, LitStr, LitBinary, Expr, ExprVec, ExprLit}; use syntax::codemap::Span; use syntax::ext::base::{DummyResult, ExtCtxt, @@ -27,6 +27,7 @@ use syntax::ext::base::{DummyResult, MacExpr}; use syntax::parse; use syntax::parse::token::{InternedString, COMMA, EOF, FAT_ARROW}; +use syntax::print::pprust; use rand::{Rng, SeedableRng, XorShiftRng}; use rustc::plugin::Registry; @@ -45,21 +46,15 @@ pub fn macro_registrar(reg: &mut Registry) { #[deriving(PartialEq, Eq, Clone)] enum Key { - StaticStr(InternedString), + KeyStr(InternedString), + KeyBinary(Rc>), } impl Hash for Key { fn hash(&self, state: &mut S) { match *self { - StaticStr(ref s) => s.get().hash(state), - } - } -} - -impl fmt::Show for Key { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - StaticStr(ref s) => s.fmt(fmt), + KeyStr(ref s) => s.get().hash(state), + KeyBinary(ref b) => b.hash(state), } } } @@ -151,7 +146,7 @@ fn parse_map(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { let key = cx.expand_expr(parser.parse_expr()); let key_contents = parse_key(cx, key).unwrap_or_else(|| { bad = true; - StaticStr(InternedString::new("")) + KeyStr(InternedString::new("")) }); if !parser.eat(&FAT_ARROW) { @@ -198,7 +193,7 @@ fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { let key = cx.expand_expr(parser.parse_expr()); let key_contents = parse_key(cx, key).unwrap_or_else(|| { bad = true; - StaticStr(InternedString::new("")) + KeyStr(InternedString::new("")) }); entries.push(Entry { @@ -231,7 +226,8 @@ fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option { match e.node { ExprLit(lit) => { match lit.node { - LitStr(ref s, _) => Some(StaticStr(s.clone())), + LitStr(ref s, _) => Some(KeyStr(s.clone())), + LitBinary(ref b) => Some(KeyBinary(b.clone())), _ => { cx.span_err(e.span, "expected string literal"); None @@ -249,18 +245,19 @@ fn has_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool { let mut dups = false; let mut strings = HashMap::new(); for entry in entries.iter() { - let spans = strings.find_or_insert(entry.key_contents.clone(), vec![]); + let &(ref mut spans, _) = strings.find_or_insert(&entry.key_contents, + (vec![], &entry.key)); spans.push(entry.key.span); } - for (key, spans) in strings.iter() { + for &(ref spans, key) in strings.values() { if spans.len() == 1 { continue; } dups = true; - cx.span_err(sp, - format!("duplicate key `{}`", key).as_slice()); + cx.span_err(sp, format!("duplicate key {}", + pprust::expr_to_str(&**key)).as_slice()); for span in spans.iter() { cx.span_note(*span, "one occurrence here"); } @@ -333,7 +330,7 @@ fn try_generate_hash(entries: &[Entry], rng: &mut XorShiftRng) let mut try_map = HashMap::new(); 'buckets: for bucket in buckets.iter() { for d1 in range(0, table_len) { - 'disps_l: for d2 in range(0, table_len) { + 'disps: for d2 in range(0, table_len) { try_map.clear(); for &key in bucket.keys.iter() { let idx = phf::displace(hashes.get(key).f1, @@ -341,7 +338,7 @@ fn try_generate_hash(entries: &[Entry], rng: &mut XorShiftRng) d1, d2) % table_len; if map.get(idx).is_some() || try_map.find(&idx).is_some() { - continue 'disps_l; + continue 'disps; } try_map.insert(idx, key); } From f3f193c4d14abef345b1caea9186f62467300214 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Jul 2014 22:16:28 -0700 Subject: [PATCH 14/30] Fix error messages --- phf_mac/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index 40153f5..6418333 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -229,13 +229,13 @@ fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option { LitStr(ref s, _) => Some(KeyStr(s.clone())), LitBinary(ref b) => Some(KeyBinary(b.clone())), _ => { - cx.span_err(e.span, "expected string literal"); + cx.span_err(e.span, "unsupported literal type"); None } } } _ => { - cx.span_err(e.span, "expected string literal"); + cx.span_err(e.span, "expected a literal"); None } } From e9644d41b57cb917d34f1e3d9cf5bb9bd7223495 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 10 Jul 2014 13:27:53 -0700 Subject: [PATCH 15/30] Update for upstream changes --- .travis.yml | 1 + Makefile.in | 12 +++++++----- phf_mac/src/lib.rs | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index baf6dbf..35784ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ env: global: - secure: ffCiAwT3mkRQ57yTyTKUV4nRsnsdDuTSXbwSFpNg/AXLn6KTt35wpp2kbKTUhU4fUikpoKh30+TMiXp1vhc7XSUo/E06JyjccRIE6oXas07NcYhYd0JRlPPWKZU8q33jvFYFB7U63vY/65tGk+wlrWm7NFyqqXwGMuysd7XT1tE= + - LD_LIBRARY_PATH: /usr/local/lib install: - curl -O http://static.rust-lang.org/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz - tar xfz rust-nightly-x86_64-unknown-linux-gnu.tar.gz diff --git a/Makefile.in b/Makefile.in index d67ab03..bf8ad9a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2,6 +2,8 @@ RUSTC := rustc BUILDDIR := build RUSTFLAGS := -O --cfg ndebug INSTALL_DIR := %PREFIX% +LD_LIBRARY_PATH := $(LD_LIBRARY_PATH):build +ENV := LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) DYLD_LIBRARY_PATH=$(LD_LIBRARY_PATH) PHF_LIB := phf/src/lib.rs PHF := $(foreach file,$(shell $(RUSTC) --print-file-name $(PHF_LIB)),$(BUILDDIR)/$(file)) @@ -22,14 +24,14 @@ $(BUILDDIR): .NOTPARALLEL: $(PHF) $(PHF): $(PHF_LIB) | $(BUILDDIR) - $(RUSTC) $(RUSTFLAGS) --dep-info $(BUILDDIR)/phf.d --out-dir $(@D) $< + $(ENV) $(RUSTC) $(RUSTFLAGS) --dep-info $(BUILDDIR)/phf.d --out-dir $(@D) $< $(PHF_MAC): $(PHF_MAC_LIB) $(PHF) | $(BUILDDIR) - $(RUSTC) $(RUSTFLAGS) --dep-info $(BUILDDIR)/phf_mac.d --out-dir $(@D) \ + $(ENV) $(RUSTC) $(RUSTFLAGS) --dep-info $(BUILDDIR)/phf_mac.d --out-dir $(@D) \ -L $(BUILDDIR) $< $(PHF_TEST): $(PHF_TEST_MAIN) $(PHF) $(PHF_MAC) | $(BUILDDIR) - $(RUSTC) --test $(RUSTFLAGS) -L $(BUILDDIR) \ + $(ENV) $(RUSTC) --test $(RUSTFLAGS) -L $(BUILDDIR) \ --dep-info $(BUILDDIR)/phf_test.d --out-dir $(@D) $< doc-test: $(PHF) $(PHF_MAC) @@ -39,8 +41,8 @@ check: $(PHF_TEST) doc-test $(PHF_TEST) doc: $(PHF) - rustdoc $(PHF_LIB) - rustdoc -L $(BUILDDIR) $(PHF_MAC_LIB) + $(ENV) rustdoc $(PHF_LIB) + $(ENV) rustdoc -L $(BUILDDIR) $(PHF_MAC_LIB) install: $(PHF) $(PHF_MAC) install $(PHF) $(INSTALL_DIR) diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index 6418333..81c5cac 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -257,7 +257,7 @@ fn has_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool { dups = true; cx.span_err(sp, format!("duplicate key {}", - pprust::expr_to_str(&**key)).as_slice()); + pprust::expr_to_string(&**key)).as_slice()); for span in spans.iter() { cx.span_note(*span, "one occurrence here"); } From 789990ede8def8c333a305437899a953ed6f9a62 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 10 Jul 2014 21:59:02 -0700 Subject: [PATCH 16/30] Byte and char key support --- phf/src/lib.rs | 8 ++++---- phf/src/test.rs | 20 ++++++++++++++++++++ phf_mac/src/lib.rs | 8 +++++++- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index f8b8459..49df08c 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -35,7 +35,7 @@ pub fn displace(f1: uint, f2: uint, d1: uint, d2: uint) -> uint { /// An immutable map constructed at compile time. /// -/// Keys may be either string literals or binary string literals. +/// Keys may be string, binary string, byte, or character literals. /// /// `PhfMap`s may be created with the `phf_map` macro: /// @@ -216,7 +216,7 @@ impl<'a, K, V> Iterator<&'a V> for PhfMapValues<'a, K, V> { /// An immutable set constructed at compile time. /// -/// Values may be either string literals or binary string literals. +/// Values may be string, binary string, byte, or character literals. /// /// `PhfSet`s may be created with the `phf_set` macro: /// @@ -325,7 +325,7 @@ impl<'a, T> Iterator<&'a T> for PhfSetValues<'a, T> { /// An order-preserving immutable map constructed at compile time. /// -/// Keys may be either string literals or binary string literals. +/// Keys may be string, binary string, byte, or character literals. /// /// Unlike a `PhfMap`, the order of entries in a `PhfOrderedMap` is guaranteed /// to be the order the entries were listed in. @@ -548,7 +548,7 @@ impl<'a, K, V> ExactSize<&'a V> for PhfOrderedMapValues<'a, K, V> {} /// An order-preserving immutable set constructed at compile time. /// -/// Values may be either string literals or binary string literals. +/// Values may be string, binary string, byte, or character literals. /// /// Unlike a `PhfSet`, the order of entries in a `PhfOrderedSet` is guaranteed /// to be the order the entries were listed in. diff --git a/phf/src/test.rs b/phf/src/test.rs index b59c5d4..9850c50 100644 --- a/phf/src/test.rs +++ b/phf/src/test.rs @@ -124,6 +124,26 @@ mod map { assert_eq!(Some(&0), map.find(&b"hello")); assert_eq!(Some(&1), map.find(&b"world")); } + + #[test] + fn test_byte_keys() { + static map: PhfMap = phf_map! { + b'a' => 0, + b'b' => 1, + }; + assert_eq!(Some(&0), map.find(&b'a')); + assert_eq!(Some(&1), map.find(&b'b')); + } + + #[test] + fn test_char_keys() { + static map: PhfMap = phf_map! { + 'a' => 0, + 'b' => 1, + }; + assert_eq!(Some(&0), map.find(&'a')); + assert_eq!(Some(&1), map.find(&'b')); + } } mod set { diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index 81c5cac..c35b9c8 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -19,7 +19,7 @@ use std::hash::{Hash}; use std::os; use std::rc::Rc; use syntax::ast; -use syntax::ast::{TokenTree, LitStr, LitBinary, Expr, ExprVec, ExprLit}; +use syntax::ast::{TokenTree, LitStr, LitBinary, LitByte, LitChar, Expr, ExprVec, ExprLit}; use syntax::codemap::Span; use syntax::ext::base::{DummyResult, ExtCtxt, @@ -48,6 +48,8 @@ pub fn macro_registrar(reg: &mut Registry) { enum Key { KeyStr(InternedString), KeyBinary(Rc>), + KeyByte(u8), + KeyChar(char), } impl Hash for Key { @@ -55,6 +57,8 @@ impl Hash for Key { match *self { KeyStr(ref s) => s.get().hash(state), KeyBinary(ref b) => b.hash(state), + KeyByte(b) => b.hash(state), + KeyChar(c) => c.hash(state), } } } @@ -228,6 +232,8 @@ fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option { match lit.node { LitStr(ref s, _) => Some(KeyStr(s.clone())), LitBinary(ref b) => Some(KeyBinary(b.clone())), + LitByte(b) => Some(KeyByte(b)), + LitChar(c) => Some(KeyChar(c)), _ => { cx.span_err(e.span, "unsupported literal type"); None From 55ededfc9ccbd3b01690e289adfc4d5e05a4064d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 10 Jul 2014 23:15:36 -0700 Subject: [PATCH 17/30] Add support for remaining literals --- phf/src/lib.rs | 11 ++----- phf/src/test.rs | 79 +++++++++++++++++++++++++++++++++++----------- phf_mac/src/lib.rs | 37 ++++++++++++++++++---- 3 files changed, 94 insertions(+), 33 deletions(-) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index 49df08c..5a4771e 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -1,4 +1,7 @@ //! Compile time optimized maps +//! +//! Keys can be string literals, byte string literals, byte literals, char +//! literals, or any of the fixed-size integral types. #![crate_name="phf"] #![doc(html_root_url="http://www.rust-ci.org/sfackler")] #![crate_type="rlib"] @@ -35,8 +38,6 @@ pub fn displace(f1: uint, f2: uint, d1: uint, d2: uint) -> uint { /// An immutable map constructed at compile time. /// -/// Keys may be string, binary string, byte, or character literals. -/// /// `PhfMap`s may be created with the `phf_map` macro: /// /// ```rust @@ -216,8 +217,6 @@ impl<'a, K, V> Iterator<&'a V> for PhfMapValues<'a, K, V> { /// An immutable set constructed at compile time. /// -/// Values may be string, binary string, byte, or character literals. -/// /// `PhfSet`s may be created with the `phf_set` macro: /// /// ```rust @@ -325,8 +324,6 @@ impl<'a, T> Iterator<&'a T> for PhfSetValues<'a, T> { /// An order-preserving immutable map constructed at compile time. /// -/// Keys may be string, binary string, byte, or character literals. -/// /// Unlike a `PhfMap`, the order of entries in a `PhfOrderedMap` is guaranteed /// to be the order the entries were listed in. /// @@ -548,8 +545,6 @@ impl<'a, K, V> ExactSize<&'a V> for PhfOrderedMapValues<'a, K, V> {} /// An order-preserving immutable set constructed at compile time. /// -/// Values may be string, binary string, byte, or character literals. -/// /// Unlike a `PhfSet`, the order of entries in a `PhfOrderedSet` is guaranteed /// to be the order the entries were listed in. /// diff --git a/phf/src/test.rs b/phf/src/test.rs index 9850c50..ee95a99 100644 --- a/phf/src/test.rs +++ b/phf/src/test.rs @@ -1,4 +1,4 @@ -#![feature(phase)] +#![feature(phase, macro_rules)] #[phase(plugin)] extern crate phf_mac; @@ -115,34 +115,75 @@ mod map { assert_eq!(Some(&0), map.find_equiv(&"a".to_string().as_slice())); } + macro_rules! test_key_type( + ($t:ty, $($k:expr => $v:expr),+) => ({ + static map: PhfMap<$t, int> = phf_map! { + $($k => $v),+ + }; + $( + assert_eq!(Some(&$v), map.find(&$k)); + )+ + }) + ) + #[test] fn test_binary_keys() { - static map: PhfMap<&'static [u8], int> = phf_map! { - b"hello" => 0, - b"world" => 1 - }; - assert_eq!(Some(&0), map.find(&b"hello")); - assert_eq!(Some(&1), map.find(&b"world")); + test_key_type!(&'static [u8], b"hello" => 0, b"world" => 1); } #[test] fn test_byte_keys() { - static map: PhfMap = phf_map! { - b'a' => 0, - b'b' => 1, - }; - assert_eq!(Some(&0), map.find(&b'a')); - assert_eq!(Some(&1), map.find(&b'b')); + test_key_type!(u8, b'a' => 0, b'b' => 1); } #[test] fn test_char_keys() { - static map: PhfMap = phf_map! { - 'a' => 0, - 'b' => 1, - }; - assert_eq!(Some(&0), map.find(&'a')); - assert_eq!(Some(&1), map.find(&'b')); + test_key_type!(char, 'a' => 0, 'b' => 1); + } + + #[test] + fn test_i8_keys() { + test_key_type!(i8, 0i8 => 0, 1i8 => 1); + } + + #[test] + fn test_i16_keys() { + test_key_type!(i16, 0i16 => 0, 1i16 => 1); + } + + #[test] + fn test_i32_keys() { + test_key_type!(i32, 0i32 => 0, 1i32 => 1); + } + + #[test] + fn test_i64_keys() { + test_key_type!(i64, 0i64 => 0, 1i64 => 1); + } + + #[test] + fn test_u8_keys() { + test_key_type!(u8, 0u8 => 0, 1u8 => 1); + } + + #[test] + fn test_u16_keys() { + test_key_type!(u16, 0u16 => 0, 1u16 => 1); + } + + #[test] + fn test_u32_keys() { + test_key_type!(u32, 0u32 => 0, 1u32 => 1); + } + + #[test] + fn test_u64_keys() { + test_key_type!(u64, 0u64 => 0, 1u64 => 1); + } + + #[test] + fn test_bool_keys() { + test_key_type!(bool, false => 0, true => 1); } } diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index c35b9c8..406c193 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -48,8 +48,16 @@ pub fn macro_registrar(reg: &mut Registry) { enum Key { KeyStr(InternedString), KeyBinary(Rc>), - KeyByte(u8), KeyChar(char), + KeyU8(u8), + KeyI8(i8), + KeyU16(u16), + KeyI16(i16), + KeyU32(u32), + KeyI32(i32), + KeyU64(u64), + KeyI64(i64), + KeyBool(bool), } impl Hash for Key { @@ -57,8 +65,16 @@ impl Hash for Key { match *self { KeyStr(ref s) => s.get().hash(state), KeyBinary(ref b) => b.hash(state), - KeyByte(b) => b.hash(state), KeyChar(c) => c.hash(state), + KeyU8(b) => b.hash(state), + KeyI8(b) => b.hash(state), + KeyU16(b) => b.hash(state), + KeyI16(b) => b.hash(state), + KeyU32(b) => b.hash(state), + KeyI32(b) => b.hash(state), + KeyU64(b) => b.hash(state), + KeyI64(b) => b.hash(state), + KeyBool(b) => b.hash(state), } } } @@ -230,10 +246,19 @@ fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option { match e.node { ExprLit(lit) => { match lit.node { - LitStr(ref s, _) => Some(KeyStr(s.clone())), - LitBinary(ref b) => Some(KeyBinary(b.clone())), - LitByte(b) => Some(KeyByte(b)), - LitChar(c) => Some(KeyChar(c)), + ast::LitStr(ref s, _) => Some(KeyStr(s.clone())), + ast::LitBinary(ref b) => Some(KeyBinary(b.clone())), + ast::LitByte(b) => Some(KeyU8(b)), + ast::LitChar(c) => Some(KeyChar(c)), + ast::LitInt(i, ast::TyI8) => Some(KeyI8(i as i8)), + ast::LitInt(i, ast::TyI16) => Some(KeyI16(i as i16)), + ast::LitInt(i, ast::TyI32) => Some(KeyI32(i as i32)), + ast::LitInt(i, ast::TyI64) => Some(KeyI64(i as i64)), + ast::LitUint(i, ast::TyU8) => Some(KeyU8(i as u8)), + ast::LitUint(i, ast::TyU16) => Some(KeyU16(i as u16)), + ast::LitUint(i, ast::TyU32) => Some(KeyU32(i as u32)), + ast::LitUint(i, ast::TyU64) => Some(KeyU64(i as u64)), + ast::LitBool(b) => Some(KeyBool(b)), _ => { cx.span_err(e.span, "unsupported literal type"); None From b83fc0814e113ce78c05d91b436c5eec3d9b30b7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 Jul 2014 13:56:34 -0700 Subject: [PATCH 18/30] Update Cargo.toml to the new `plugin = true` flag --- phf_mac/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phf_mac/Cargo.toml b/phf_mac/Cargo.toml index 00f56a9..80addf7 100644 --- a/phf_mac/Cargo.toml +++ b/phf_mac/Cargo.toml @@ -8,7 +8,7 @@ version = "0.0.0" name = "phf_mac" path = "src/lib.rs" -crate_type = ["dylib"] +plugin = true [dependencies.phf] From b89cc89a8ff96012ea66d9bfe9d7641c3ff05d61 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Jul 2014 16:27:56 -0700 Subject: [PATCH 19/30] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a64a927..7241b86 100644 --- a/README.md +++ b/README.md @@ -24,13 +24,13 @@ extern crate phf; use phf::PhfMap; -static KEYWORDS: PhfMap = phf_map!( +static KEYWORDS: PhfMap<&'static str, Keyword> = phf_map! { "loop" => LOOP, "continue" => CONTINUE, "break" => BREAK, "fn" => FN, "extern" => EXTERN, -); +}; pub fn parse_keyword(keyword: &str) -> Option { KEYWORDS.find(keyword).map(|t| t.clone()) From 4b4897284da11b59b4122c4b0c10b23064ca380c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Jul 2014 00:09:14 -0700 Subject: [PATCH 20/30] Implement more iterator traits for PhfMap iters --- phf/src/lib.rs | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index 5a4771e..8c71e3e 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -185,6 +185,14 @@ impl<'a, K, V> Iterator<&'a (K, V)> for PhfMapEntries<'a, K, V> { } } +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, V> { iter: PhfMapEntries<'a, K, V>, @@ -192,7 +200,7 @@ pub struct PhfMapKeys<'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().map(|&(ref key, _)| key) + self.iter.next().map(|&(ref k, _)| k) } fn size_hint(&self) -> (uint, Option) { @@ -200,6 +208,14 @@ impl<'a, K, V> Iterator<&'a K> for PhfMapKeys<'a, K, V> { } } +impl<'a, K, V> DoubleEndedIterator<&'a K> for PhfMapKeys<'a, K, V> { + fn next_back(&mut self) -> Option<&'a K> { + self.iter.next_back().map(|&(ref k, _)| k) + } +} + +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, V> { iter: PhfMapEntries<'a, K, V>, @@ -207,7 +223,7 @@ pub struct PhfMapValues<'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().map(|&(_, ref value)| value) + self.iter.next().map(|&(_, ref v)| v) } fn size_hint(&self) -> (uint, Option) { @@ -215,6 +231,14 @@ impl<'a, K, V> Iterator<&'a V> for PhfMapValues<'a, K, V> { } } +impl<'a, K, V> DoubleEndedIterator<&'a V> for PhfMapValues<'a, K, V> { + fn next_back(&mut self) -> Option<&'a V> { + self.iter.next_back().map(|&(_, ref v)| v) + } +} + +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: @@ -311,17 +335,23 @@ pub struct PhfSetValues<'a, T> { } impl<'a, T> Iterator<&'a T> for PhfSetValues<'a, T> { - #[inline] fn next(&mut self) -> Option<&'a T> { self.iter.next() } - #[inline] fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } } +impl<'a, T> DoubleEndedIterator<&'a T> for PhfSetValues<'a, T> { + fn next_back(&mut self) -> Option<&'a T> { + self.iter.next_back() + } +} + +impl<'a, T> ExactSize<&'a T> for PhfSetValues<'a, T> {} + /// An order-preserving immutable map constructed at compile time. /// /// Unlike a `PhfMap`, the order of entries in a `PhfOrderedMap` is guaranteed From a8bb8156d513d0e15c476baac13a8d153f740958 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Jul 2014 00:18:10 -0700 Subject: [PATCH 21/30] Move iterator maps to construction time --- phf/src/lib.rs | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index 8c71e3e..7113343 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -11,6 +11,7 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::hash::sip::SipHasher; +use std::iter; use std::slice; use std::collections::Collection; @@ -159,14 +160,14 @@ impl PhfMap { /// /// Keys are returned in an arbitrary but fixed order. pub fn keys<'a>(&'a self) -> PhfMapKeys<'a, K, V> { - PhfMapKeys { iter: self.entries() } + PhfMapKeys { iter: self.entries().map(|&(ref k, _)| k) } } /// 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() } + PhfMapValues { iter: self.entries().map(|&(_, ref v)| v) } } } @@ -195,12 +196,12 @@ 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, V> { - iter: PhfMapEntries<'a, K, V>, + 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().map(|&(ref k, _)| k) + self.iter.next() } fn size_hint(&self) -> (uint, Option) { @@ -210,7 +211,7 @@ impl<'a, K, V> Iterator<&'a K> for PhfMapKeys<'a, K, V> { impl<'a, K, V> DoubleEndedIterator<&'a K> for PhfMapKeys<'a, K, V> { fn next_back(&mut self) -> Option<&'a K> { - self.iter.next_back().map(|&(ref k, _)| k) + self.iter.next_back() } } @@ -218,12 +219,12 @@ 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, V> { - iter: PhfMapEntries<'a, K, V>, + 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().map(|&(_, ref v)| v) + self.iter.next() } fn size_hint(&self) -> (uint, Option) { @@ -233,7 +234,7 @@ impl<'a, K, V> Iterator<&'a V> for PhfMapValues<'a, K, V> { impl<'a, K, V> DoubleEndedIterator<&'a V> for PhfMapValues<'a, K, V> { fn next_back(&mut self) -> Option<&'a V> { - self.iter.next_back().map(|&(_, ref v)| v) + self.iter.next_back() } } @@ -461,14 +462,14 @@ impl PhfOrderedMap { /// /// Keys are returned in the same order in which they were defined. pub fn keys<'a>(&'a self) -> PhfOrderedMapKeys<'a, K, V> { - PhfOrderedMapKeys { iter: self.entries() } + PhfOrderedMapKeys { iter: self.entries().map(|&(ref k, _)| k) } } /// Returns an iterator over the values in the map. /// /// Values are returned in the same order in which they were defined. pub fn values<'a>(&'a self) -> PhfOrderedMapValues<'a, K, V> { - PhfOrderedMapValues { iter: self.entries() } + PhfOrderedMapValues { iter: self.entries().map(|&(_, ref v)| v) } } } @@ -509,12 +510,12 @@ impl<'a, K, V> ExactSize<&'a (K, V)> for PhfOrderedMapEntries<'a, K, V> {} /// An iterator over the keys in a `PhfOrderedMap`. pub struct PhfOrderedMapKeys<'a, K, V> { - iter: PhfOrderedMapEntries<'a, K, V>, + iter: iter::Map<'a, &'a (K, V), &'a K, PhfOrderedMapEntries<'a, K, V>>, } impl<'a, K, V> Iterator<&'a K> for PhfOrderedMapKeys<'a, K, V> { fn next(&mut self) -> Option<&'a K> { - self.iter.next().map(|&(ref key, _)| key) + self.iter.next() } fn size_hint(&self) -> (uint, Option) { @@ -524,7 +525,7 @@ impl<'a, K, V> Iterator<&'a K> for PhfOrderedMapKeys<'a, K, V> { impl<'a, K, V> DoubleEndedIterator<&'a K> for PhfOrderedMapKeys<'a, K, V> { fn next_back(&mut self) -> Option<&'a K> { - self.iter.next_back().map(|&(ref key, _)| key) + self.iter.next_back() } } @@ -534,7 +535,7 @@ impl<'a, K, V> RandomAccessIterator<&'a K> for PhfOrderedMapKeys<'a, K, V> { } fn idx(&mut self, index: uint) -> Option<&'a K> { - self.iter.idx(index).map(|&(ref key, _)| key) + self.iter.idx(index) } } @@ -542,12 +543,12 @@ impl<'a, K, V> ExactSize<&'a K> for PhfOrderedMapKeys<'a, K, V> {} /// An iterator over the values in a `PhfOrderedMap`. pub struct PhfOrderedMapValues<'a, K, V> { - iter: PhfOrderedMapEntries<'a, K, V>, + iter: iter::Map<'a, &'a (K, V), &'a V, PhfOrderedMapEntries<'a, K, V>>, } impl<'a, K, V> Iterator<&'a V> for PhfOrderedMapValues<'a, K, V> { fn next(&mut self) -> Option<&'a V> { - self.iter.next().map(|&(_, ref value)| value) + self.iter.next() } fn size_hint(&self) -> (uint, Option) { @@ -557,7 +558,7 @@ impl<'a, K, V> Iterator<&'a V> for PhfOrderedMapValues<'a, K, V> { impl<'a, K, V> DoubleEndedIterator<&'a V> for PhfOrderedMapValues<'a, K, V> { fn next_back(&mut self) -> Option<&'a V> { - self.iter.next_back().map(|&(_, ref value)| value) + self.iter.next_back() } } @@ -567,7 +568,7 @@ impl<'a, K, V> RandomAccessIterator<&'a V> for PhfOrderedMapValues<'a, K, V> { } fn idx(&mut self, index: uint) -> Option<&'a V> { - self.iter.idx(index).map(|&(_, ref value)| value) + self.iter.idx(index) } } From 19c4f8d420d3a9ff8e3ace0256198f5db9fccae0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Jul 2014 12:52:03 -0700 Subject: [PATCH 22/30] Pull shared code into a module This implements @glennw's PR #5 to move the hashing code used by both phf and phf_mac into a module imported by both crates. It breaks the hard dependency of phf_mac on phf, which means phf doesn't have to be compiled for the host architecture as well as the target. It also means we can have a dev-dependency from phf to phf_mac for tests. --- Makefile.in | 2 +- phf/Cargo.toml | 9 +++++++++ phf/src/lib.rs | 34 +++++++--------------------------- phf_mac/Cargo.toml | 4 ---- phf_mac/src/lib.rs | 24 +++++++++++++----------- phf_shared/mod.rs | 19 +++++++++++++++++++ 6 files changed, 49 insertions(+), 43 deletions(-) create mode 100644 phf_shared/mod.rs diff --git a/Makefile.in b/Makefile.in index bf8ad9a..29eceee 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,7 +26,7 @@ $(BUILDDIR): $(PHF): $(PHF_LIB) | $(BUILDDIR) $(ENV) $(RUSTC) $(RUSTFLAGS) --dep-info $(BUILDDIR)/phf.d --out-dir $(@D) $< -$(PHF_MAC): $(PHF_MAC_LIB) $(PHF) | $(BUILDDIR) +$(PHF_MAC): $(PHF_MAC_LIB) | $(BUILDDIR) $(ENV) $(RUSTC) $(RUSTFLAGS) --dep-info $(BUILDDIR)/phf_mac.d --out-dir $(@D) \ -L $(BUILDDIR) $< diff --git a/phf/Cargo.toml b/phf/Cargo.toml index b0249b8..ceb1290 100644 --- a/phf/Cargo.toml +++ b/phf/Cargo.toml @@ -8,3 +8,12 @@ version = "0.0.0" name = "phf" path = "src/lib.rs" + +[dev_dependencies.phf_mac] + +path = "../phf_mac" + +[[test]] + +name = "test" +path = "src/test.rs" \ No newline at end of file diff --git a/phf/src/lib.rs b/phf/src/lib.rs index 7113343..ed86ef1 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -9,33 +9,13 @@ #![warn(missing_doc)] use std::fmt; -use std::hash::{Hash, Hasher}; -use std::hash::sip::SipHasher; +use std::hash::Hash; use std::iter; use std::slice; use std::collections::Collection; -static LOG_MAX_SIZE: uint = 21; - -#[doc(hidden)] -pub static MAX_SIZE: uint = 1 << LOG_MAX_SIZE; - -#[doc(hidden)] -#[inline] -pub fn hash(s: &T, k1: u64, k2: u64) -> (uint, uint, uint) { - let hash = SipHasher::new_with_keys(k1, k2).hash(s); - let mask = (MAX_SIZE - 1) as u64; - - ((hash & mask) as uint, - ((hash >> LOG_MAX_SIZE) & mask) as uint, - ((hash >> (2 * LOG_MAX_SIZE)) & mask) as uint) -} - -#[doc(hidden)] -#[inline] -pub fn displace(f1: uint, f2: uint, d1: uint, d2: uint) -> uint { - d2 + f1 * d1 + f2 -} +#[path="../../phf_shared/mod.rs"] +mod phf_shared; /// An immutable map constructed at compile time. /// @@ -106,9 +86,9 @@ impl fmt::Show for PhfMap { impl PhfMap { fn get_entry<'a, T: Hash>(&'a self, key: &T, check: |&K| -> bool) -> Option<&'a (K, V)> { - let (g, f1, f2) = hash(key, self.k1, self.k2); + let (g, f1, f2) = phf_shared::hash(key, self.k1, self.k2); let (d1, d2) = self.disps[g % self.disps.len()]; - let entry @ &(ref s, _) = &self.entries[displace(f1, f2, d1, d2) % + let entry @ &(ref s, _) = &self.entries[phf_shared::displace(f1, f2, d1, d2) % self.entries.len()]; if check(s) { Some(entry) @@ -426,9 +406,9 @@ impl<'a, K: Hash+Eq, V> Map for PhfOrderedMap { impl PhfOrderedMap { fn find_entry<'a>(&'a self, key: &K) -> Option<&'a (K, V)> { - let (g, f1, f2) = hash(key, self.k1, self.k2); + let (g, f1, f2) = phf_shared::hash(key, self.k1, self.k2); let (d1, d2) = self.disps[g % self.disps.len()]; - let idx = self.idxs[displace(f1, f2, d1, d2) % self.idxs.len()]; + let idx = self.idxs[phf_shared::displace(f1, f2, d1, d2) % self.idxs.len()]; let entry @ &(ref s, _) = &self.entries[idx]; if s == key { diff --git a/phf_mac/Cargo.toml b/phf_mac/Cargo.toml index 80addf7..28e22c8 100644 --- a/phf_mac/Cargo.toml +++ b/phf_mac/Cargo.toml @@ -9,7 +9,3 @@ version = "0.0.0" name = "phf_mac" path = "src/lib.rs" plugin = true - -[dependencies.phf] - -path = "../phf" diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index 406c193..d9ccd9a 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -9,13 +9,12 @@ extern crate rand; extern crate syntax; extern crate time; -extern crate phf; extern crate rustc; use std::collections::HashMap; use std::gc::{Gc, GC}; use std::hash; -use std::hash::{Hash}; +use std::hash::Hash; use std::os; use std::rc::Rc; use syntax::ast; @@ -31,6 +30,9 @@ use syntax::print::pprust; use rand::{Rng, SeedableRng, XorShiftRng}; use rustc::plugin::Registry; +#[path="../../phf_shared/mod.rs"] +mod phf_shared; + static DEFAULT_LAMBDA: uint = 5; static FIXED_SEED: [u32, ..4] = [3141592653, 589793238, 462643383, 2795028841]; @@ -188,10 +190,10 @@ fn parse_map(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { } } - if entries.len() > phf::MAX_SIZE { + if entries.len() > phf_shared::MAX_SIZE { cx.span_err(parser.span, format!("maps with more than {} entries are not supported", - phf::MAX_SIZE).as_slice()); + phf_shared::MAX_SIZE).as_slice()); return None; } @@ -228,10 +230,10 @@ fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { } } - if entries.len() > phf::MAX_SIZE { + if entries.len() > phf_shared::MAX_SIZE { cx.span_err(parser.span, format!("maps with more than {} entries are not supported", - phf::MAX_SIZE).as_slice()); + phf_shared::MAX_SIZE).as_slice()); return None; } @@ -336,7 +338,7 @@ fn try_generate_hash(entries: &[Entry], rng: &mut XorShiftRng) let k2 = rng.gen(); let hashes: Vec = entries.iter().map(|entry| { - let (g, f1, f2) = phf::hash(&entry.key_contents, k1, k2); + let (g, f1, f2) = phf_shared::hash(&entry.key_contents, k1, k2); Hashes { g: g, f1: f1, @@ -364,10 +366,10 @@ fn try_generate_hash(entries: &[Entry], rng: &mut XorShiftRng) 'disps: for d2 in range(0, table_len) { try_map.clear(); for &key in bucket.keys.iter() { - let idx = phf::displace(hashes.get(key).f1, - hashes.get(key).f2, - d1, - d2) % table_len; + let idx = phf_shared::displace(hashes.get(key).f1, + hashes.get(key).f2, + d1, + d2) % table_len; if map.get(idx).is_some() || try_map.find(&idx).is_some() { continue 'disps; } diff --git a/phf_shared/mod.rs b/phf_shared/mod.rs new file mode 100644 index 0000000..be451e0 --- /dev/null +++ b/phf_shared/mod.rs @@ -0,0 +1,19 @@ +use std::hash::{Hash, Hasher}; +use std::hash::sip::SipHasher; + +static LOG_MAX_SIZE: uint = 21; + +pub static MAX_SIZE: uint = 1 << LOG_MAX_SIZE; + +pub fn hash(s: &T, k1: u64, k2: u64) -> (uint, uint, uint) { + let hash = SipHasher::new_with_keys(k1, k2).hash(s); + let mask = (MAX_SIZE - 1) as u64; + + ((hash & mask) as uint, + ((hash >> LOG_MAX_SIZE) & mask) as uint, + ((hash >> (2 * LOG_MAX_SIZE)) & mask) as uint) +} + +pub fn displace(f1: uint, f2: uint, d1: uint, d2: uint) -> uint { + d2 + f1 * d1 + f2 +} From 6718b60a55939992b7d4c5c00f57a4a81f38e5ac Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Jul 2014 13:23:13 -0700 Subject: [PATCH 23/30] Turn off tests for main crates --- phf/Cargo.toml | 1 + phf_mac/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/phf/Cargo.toml b/phf/Cargo.toml index ceb1290..f0471ad 100644 --- a/phf/Cargo.toml +++ b/phf/Cargo.toml @@ -8,6 +8,7 @@ version = "0.0.0" name = "phf" path = "src/lib.rs" +test = false [dev_dependencies.phf_mac] diff --git a/phf_mac/Cargo.toml b/phf_mac/Cargo.toml index 28e22c8..f3d68eb 100644 --- a/phf_mac/Cargo.toml +++ b/phf_mac/Cargo.toml @@ -9,3 +9,4 @@ version = "0.0.0" name = "phf_mac" path = "src/lib.rs" plugin = true +test = false From 6372fa437f01de39cc80120f9d9ed48cee0f0b1f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Jul 2014 13:34:59 -0700 Subject: [PATCH 24/30] Rename phf_shared to phf --- phf/src/lib.rs | 2 +- phf_mac/src/lib.rs | 2 +- {phf_shared => shared}/mod.rs | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename {phf_shared => shared}/mod.rs (100%) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index ed86ef1..e101cb7 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -14,7 +14,7 @@ use std::iter; use std::slice; use std::collections::Collection; -#[path="../../phf_shared/mod.rs"] +#[path="../../shared/mod.rs"] mod phf_shared; /// An immutable map constructed at compile time. diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index d9ccd9a..2deed94 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -30,7 +30,7 @@ use syntax::print::pprust; use rand::{Rng, SeedableRng, XorShiftRng}; use rustc::plugin::Registry; -#[path="../../phf_shared/mod.rs"] +#[path="../../shared/mod.rs"] mod phf_shared; static DEFAULT_LAMBDA: uint = 5; diff --git a/phf_shared/mod.rs b/shared/mod.rs similarity index 100% rename from phf_shared/mod.rs rename to shared/mod.rs From 25aeba6aeeb9f14ebabf11cd368f22840d40a245 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Jul 2014 13:36:12 -0700 Subject: [PATCH 25/30] Rename module --- phf/src/lib.rs | 10 +++++----- phf_mac/src/lib.rs | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index e101cb7..f093256 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -15,7 +15,7 @@ use std::slice; use std::collections::Collection; #[path="../../shared/mod.rs"] -mod phf_shared; +mod shared; /// An immutable map constructed at compile time. /// @@ -86,9 +86,9 @@ impl fmt::Show for PhfMap { impl PhfMap { fn get_entry<'a, T: Hash>(&'a self, key: &T, check: |&K| -> bool) -> Option<&'a (K, V)> { - let (g, f1, f2) = phf_shared::hash(key, self.k1, self.k2); + let (g, f1, f2) = shared::hash(key, self.k1, self.k2); let (d1, d2) = self.disps[g % self.disps.len()]; - let entry @ &(ref s, _) = &self.entries[phf_shared::displace(f1, f2, d1, d2) % + let entry @ &(ref s, _) = &self.entries[shared::displace(f1, f2, d1, d2) % self.entries.len()]; if check(s) { Some(entry) @@ -406,9 +406,9 @@ impl<'a, K: Hash+Eq, V> Map for PhfOrderedMap { impl PhfOrderedMap { fn find_entry<'a>(&'a self, key: &K) -> Option<&'a (K, V)> { - let (g, f1, f2) = phf_shared::hash(key, self.k1, self.k2); + let (g, f1, f2) = shared::hash(key, self.k1, self.k2); let (d1, d2) = self.disps[g % self.disps.len()]; - let idx = self.idxs[phf_shared::displace(f1, f2, d1, d2) % self.idxs.len()]; + let idx = self.idxs[shared::displace(f1, f2, d1, d2) % self.idxs.len()]; let entry @ &(ref s, _) = &self.entries[idx]; if s == key { diff --git a/phf_mac/src/lib.rs b/phf_mac/src/lib.rs index 2deed94..d519be4 100644 --- a/phf_mac/src/lib.rs +++ b/phf_mac/src/lib.rs @@ -31,7 +31,7 @@ use rand::{Rng, SeedableRng, XorShiftRng}; use rustc::plugin::Registry; #[path="../../shared/mod.rs"] -mod phf_shared; +mod shared; static DEFAULT_LAMBDA: uint = 5; @@ -190,10 +190,10 @@ fn parse_map(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { } } - if entries.len() > phf_shared::MAX_SIZE { + if entries.len() > shared::MAX_SIZE { cx.span_err(parser.span, format!("maps with more than {} entries are not supported", - phf_shared::MAX_SIZE).as_slice()); + shared::MAX_SIZE).as_slice()); return None; } @@ -230,10 +230,10 @@ fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { } } - if entries.len() > phf_shared::MAX_SIZE { + if entries.len() > shared::MAX_SIZE { cx.span_err(parser.span, format!("maps with more than {} entries are not supported", - phf_shared::MAX_SIZE).as_slice()); + shared::MAX_SIZE).as_slice()); return None; } @@ -338,7 +338,7 @@ fn try_generate_hash(entries: &[Entry], rng: &mut XorShiftRng) let k2 = rng.gen(); let hashes: Vec = entries.iter().map(|entry| { - let (g, f1, f2) = phf_shared::hash(&entry.key_contents, k1, k2); + let (g, f1, f2) = shared::hash(&entry.key_contents, k1, k2); Hashes { g: g, f1: f1, @@ -366,10 +366,10 @@ fn try_generate_hash(entries: &[Entry], rng: &mut XorShiftRng) 'disps: for d2 in range(0, table_len) { try_map.clear(); for &key in bucket.keys.iter() { - let idx = phf_shared::displace(hashes.get(key).f1, - hashes.get(key).f2, - d1, - d2) % table_len; + let idx = shared::displace(hashes.get(key).f1, + hashes.get(key).f2, + d1, + d2) % table_len; if map.get(idx).is_some() || try_map.find(&idx).is_some() { continue 'disps; } From 95f3c9074392b7782d28e6a94e79dfc303066ea2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Jul 2014 22:41:46 -0700 Subject: [PATCH 26/30] Switch Travis to using cargo --- .travis.yml | 11 +++++------ phf/src/lib.rs | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 35784ef..80b5505 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,12 +3,11 @@ env: - secure: ffCiAwT3mkRQ57yTyTKUV4nRsnsdDuTSXbwSFpNg/AXLn6KTt35wpp2kbKTUhU4fUikpoKh30+TMiXp1vhc7XSUo/E06JyjccRIE6oXas07NcYhYd0JRlPPWKZU8q33jvFYFB7U63vY/65tGk+wlrWm7NFyqqXwGMuysd7XT1tE= - LD_LIBRARY_PATH: /usr/local/lib install: - - curl -O http://static.rust-lang.org/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz - - tar xfz rust-nightly-x86_64-unknown-linux-gnu.tar.gz - - (cd rust-nightly-x86_64-unknown-linux-gnu/ && sudo ./install.sh) -before_script: - - ./configure + - curl http://www.rust-lang.org/rustup.sh | sudo sh - script: - - make all check doc + - cd phf && cargo test + - cd phf && rustdoc -L target/test -L target/test/deps --test src/lib.rs + - rustdoc -L phf/target/test -L phf/target/test/deps phf/src/lib.rs + - rustdoc phf_mac/src/lib.rs after_script: - curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh diff --git a/phf/src/lib.rs b/phf/src/lib.rs index f093256..aeaa2f3 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -110,7 +110,7 @@ impl PhfMap { /// Like `find`, but can operate on any type that is equivalent to a key. pub fn find_equiv<'a, T: Hash+Equiv>(&'a self, key: &T) - -> Option<&'a V> { + -> Option<&'a V> { self.get_entry(key, |k| key.equiv(k)).map(|e| { let &(_, ref v) = e; v @@ -120,7 +120,7 @@ impl PhfMap { /// Like `find_key`, but can operate on any type that is equivalent to a /// key. pub fn find_key_equiv<'a, T: Hash+Equiv>(&'a self, key: &T) - -> Option<&'a K> { + -> Option<&'a K> { self.get_entry(key, |k| key.equiv(k)).map(|e| { let &(ref k, _) = e; k From 9a7b99af87ea0c22e25626a864f621e20b367ac5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Jul 2014 22:44:12 -0700 Subject: [PATCH 27/30] Fix travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80b5505..a9a0919 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,8 @@ env: install: - curl http://www.rust-lang.org/rustup.sh | sudo sh - script: - - cd phf && cargo test - - cd phf && rustdoc -L target/test -L target/test/deps --test src/lib.rs + - (cd phf && cargo test) + - (cd phf && rustdoc -L target/test -L target/test/deps --test src/lib.rs) - rustdoc -L phf/target/test -L phf/target/test/deps phf/src/lib.rs - rustdoc phf_mac/src/lib.rs after_script: From 902c79deaafa1f952e7dafa9872314ff6402af96 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Jul 2014 23:25:34 -0700 Subject: [PATCH 28/30] Remove LD_LIBRARY_PATH override from travis config --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a9a0919..20b3c82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ env: global: - secure: ffCiAwT3mkRQ57yTyTKUV4nRsnsdDuTSXbwSFpNg/AXLn6KTt35wpp2kbKTUhU4fUikpoKh30+TMiXp1vhc7XSUo/E06JyjccRIE6oXas07NcYhYd0JRlPPWKZU8q33jvFYFB7U63vY/65tGk+wlrWm7NFyqqXwGMuysd7XT1tE= - - LD_LIBRARY_PATH: /usr/local/lib install: - curl http://www.rust-lang.org/rustup.sh | sudo sh - script: From 9822d1683465af5be8b4a1e16cbaa5cc54870057 Mon Sep 17 00:00:00 2001 From: Jack Moffitt Date: Wed, 23 Jul 2014 17:37:45 -0600 Subject: [PATCH 29/30] Fixup makefile for new upstream changes. --- Makefile.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.in b/Makefile.in index d2ea20c..89b4d18 100644 --- a/Makefile.in +++ b/Makefile.in @@ -6,21 +6,21 @@ RUSTFLAGS ?= -O HOST_RUSTFLAGS ?= -O -PHF_SRC := $(VPATH)/src/phf.rs -PHF_MAC_SRC := $(VPATH)/src/phf_mac.rs -PHF_TEST_SRC := $(VPATH)/src/test.rs +PHF_SRC := $(VPATH)/phf/src/lib.rs +PHF_MAC_SRC := $(VPATH)/phf_mac/src/lib.rs +PHF_TEST_SRC := $(VPATH)/phf/src/test.rs all: phf.dummy phf_host.dummy phf_mac.dummy phf.dummy: $(PHF_SRC) - $(RUSTC) $(RUSTFLAGS) $< --out-dir . + $(RUSTC) $(RUSTFLAGS) $< --out-dir . --crate-type rlib touch $@ # phf_mac depends on phf, so it must be built once for # the target platform, and again for the host platform. phf_host.dummy: $(PHF_SRC) mkdir -p host - $(RUSTC) $(HOST_RUSTFLAGS) $< --out-dir host + $(RUSTC) $(HOST_RUSTFLAGS) $< --out-dir host --crate-type rlib touch $@ phf_mac.dummy: $(PHF_MAC_SRC) phf_host.dummy From 04e048fbe017e5096e56b722ba640fbc77ae42bb Mon Sep 17 00:00:00 2001 From: Jack Moffitt Date: Thu, 24 Jul 2014 14:36:50 -0600 Subject: [PATCH 30/30] Backport missing methods for PhfOrderedMap. --- phf/src/lib.rs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/phf/src/lib.rs b/phf/src/lib.rs index fc7a3bb..004f11b 100644 --- a/phf/src/lib.rs +++ b/phf/src/lib.rs @@ -396,7 +396,7 @@ impl Collection for PhfOrderedMap { impl<'a, K: Hash+Eq, V> Map for PhfOrderedMap { fn find<'a>(&'a self, key: &K) -> Option<&'a V> { - self.find_entry(key).map(|e| { + self.get_entry(key, |k| key == k).map(|e| { let &(_, ref v) = e; v }) @@ -404,13 +404,14 @@ impl<'a, K: Hash+Eq, V> Map for PhfOrderedMap { } impl PhfOrderedMap { - fn find_entry<'a>(&'a self, key: &K) -> Option<&'a (K, V)> { + fn get_entry<'a, T: Hash>(&'a self, key: &T, check: |&K| -> bool) + -> Option<&'a (K, V)> { let (g, f1, f2) = shared::hash(key, self.k1, self.k2); let (d1, d2) = self.disps[g % self.disps.len()]; let idx = self.idxs[shared::displace(f1, f2, d1, d2) % self.idxs.len()]; let entry @ &(ref s, _) = &self.entries[idx]; - if s == key { + if check(s) { Some(entry) } else { None @@ -422,7 +423,26 @@ impl PhfOrderedMap { /// /// This can be useful for interning schemes. pub fn find_key<'a>(&'a self, key: &K) -> Option<&'a K> { - self.find_entry(key).map(|e| { + self.get_entry(key, |k| key == k).map(|e| { + let &(ref k, _) = e; + k + }) + } + + /// Like `find`, but can operate on any type that is equivalent to a key. + pub fn find_equiv<'a, T: Hash+Equiv>(&'a self, key: &T) + -> Option<&'a V> { + self.get_entry(key, |k| key.equiv(k)).map(|e| { + let &(_, ref v) = e; + v + }) + } + + /// Like `find_key`, but can operate on any type that is equivalent to a + /// key. + pub fn find_key_equiv<'a, T: Hash+Equiv>(&'a self, key: &T) + -> Option<&'a K> { + self.get_entry(key, |k| key.equiv(k)).map(|e| { let &(ref k, _) = e; k })