Skip to content

Commit

Permalink
Add a crate to build PHF data types at runtime
Browse files Browse the repository at this point in the history
Closes #79
  • Loading branch information
sfackler committed Mar 6, 2016
1 parent 0cc3844 commit 67b00ba
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 0 deletions.
8 changes: 8 additions & 0 deletions phf_builder/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "phf_builder"
version = "0.7.13"
authors = ["Steven Fackler <sfackler@gmail.com>"]

[dependencies]
phf = { version = "=0.7.13", path = "../phf" }
phf_generator = { version = "=0.7.13", path = "../phf_generator" }
175 changes: 175 additions & 0 deletions phf_builder/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
#![doc(html_root_url="http://sfackler.github.io/rust-phf/doc/v0.7.13")]
extern crate phf;
extern crate phf_generator;

#[cfg(test)]
mod test;

use phf::PhfHash;
use std::collections::HashSet;
use std::hash::Hash;

/// A builder for the `phf::Map` type.
pub struct Map<K, V> {
keys: Vec<K>,
values: Vec<V>,
}

impl<K: Hash + PhfHash + Eq, V> Map<K, V> {
/// Creates a new `phf::Map` builder.
pub fn new() -> Map<K, V> {
Map {
keys: vec![],
values: vec![],
}
}

/// Adds an entry to the builder.
pub fn entry(&mut self, key: K, value: V) -> &mut Map<K, V> {
self.keys.push(key);
self.values.push(value);
self
}

/// Constructs a `phf::Map`.
///
/// # Panics
///
/// Panics if there are any duplicate keys.
pub fn build(self) -> phf::Map<K, V> {
{
let mut set = HashSet::new();
for key in &self.keys {
if !set.insert(key) {
panic!("duplicate key");
}
}
}

let state = phf_generator::generate_hash(&self.keys);

let mut entries = self.keys
.into_iter()
.zip(self.values)
.map(Option::Some)
.collect::<Vec<_>>();
let entries = state.map
.iter()
.map(|&i| entries[i].take().unwrap())
.collect();

phf::Map {
key: state.key,
disps: phf::Slice::Dynamic(state.disps),
entries: phf::Slice::Dynamic(entries),
}
}
}

/// A builder for the `phf::Set` type.
pub struct Set<T> {
map: Map<T, ()>,
}

impl<T: Hash + PhfHash + Eq> Set<T> {
/// Constructs a new `phf::Set` builder.
pub fn new() -> Set<T> {
Set { map: Map::new() }
}

/// Adds an entry to the builder.
pub fn entry(&mut self, entry: T) -> &mut Set<T> {
self.map.entry(entry, ());
self
}

/// Constructs a `phf::Set`.
///
/// # Panics
///
/// Panics if there are any duplicate entries.
pub fn build(self) -> phf::Set<T> {
phf::Set {
map: self.map.build()
}
}
}

/// A builder for the `phf::OrderedMap` type.
pub struct OrderedMap<K, V> {
keys: Vec<K>,
values: Vec<V>,
}

impl<K: Hash + PhfHash + Eq, V> OrderedMap<K, V> {
/// Constructs a enw `phf::OrderedMap` builder.
pub fn new() -> OrderedMap<K, V> {
OrderedMap {
keys: vec![],
values: vec![],
}
}

/// Adds an entry to the builder.
pub fn entry(&mut self, key: K, value: V) -> &mut OrderedMap<K, V> {
self.keys.push(key);
self.values.push(value);
self
}

/// Constructs a `phf::OrderedMap`.
///
/// # Panics
///
/// Panics if there are any duplicate keys.
pub fn build(self) -> phf::OrderedMap<K, V> {
{
let mut set = HashSet::new();
for key in &self.keys {
if !set.insert(key) {
panic!("duplicate key");
}
}
}

let state = phf_generator::generate_hash(&self.keys);

let entries = self.keys.into_iter().zip(self.values).collect();

phf::OrderedMap {
key: state.key,
disps: phf::Slice::Dynamic(state.disps),
idxs: phf::Slice::Dynamic(state.map),
entries: phf::Slice::Dynamic(entries),
}
}
}

/// A builder for the `phf::OrderedSet` type.
pub struct OrderedSet<T> {
map: OrderedMap<T, ()>,
}

impl<T: Hash + PhfHash + Eq> OrderedSet<T> {
/// Constructs a new `phf::OrderedSet` builder.
pub fn new() -> OrderedSet<T> {
OrderedSet { map: OrderedMap::new() }
}

/// Adds an entry to the builder.
pub fn entry(&mut self, entry: T) -> &mut OrderedSet<T> {
self.map.entry(entry, ());
self
}

/// Constructs a `phf::OrderedSet`.
///
/// # Panics
///
/// Panics if there are any duplicate entries.
pub fn build(self) -> phf::OrderedSet<T> {
phf::OrderedSet {
map: self.map.build(),
}
}
}
47 changes: 47 additions & 0 deletions phf_builder/src/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use {Map, Set, OrderedMap, OrderedSet};

#[test]
fn map() {
let mut builder = Map::new();
builder.entry(1, "a").entry(2, "b").entry(3, "c");
let map = builder.build();
assert_eq!("a", map[&1]);
assert_eq!("b", map[&2]);
assert_eq!("c", map[&3]);
assert!(!map.contains_key(&100));
}

#[test]
fn set() {
let mut builder = Set::new();
builder.entry(1).entry(2).entry(3);
let set = builder.build();
assert!(set.contains(&1));
assert!(set.contains(&2));
assert!(set.contains(&3));
assert!(!set.contains(&4));
}

#[test]
fn ordered_map() {
let mut builder = OrderedMap::new();
builder.entry(1, "a").entry(2, "b").entry(3, "c");
let map = builder.build();
assert_eq!("a", map[&1]);
assert_eq!("b", map[&2]);
assert_eq!("c", map[&3]);
assert!(!map.contains_key(&100));
assert_eq!(&["a", "b", "c"][..], &map.values().cloned().collect::<Vec<_>>()[..]);
}

#[test]
fn ordered_set() {
let mut builder = OrderedSet::new();
builder.entry(1).entry(2).entry(3);
let set = builder.build();
assert!(set.contains(&1));
assert!(set.contains(&2));
assert!(set.contains(&3));
assert!(!set.contains(&4));
assert_eq!(&[1, 2, 3][..], &set.iter().cloned().collect::<Vec<_>>()[..]);
}

0 comments on commit 67b00ba

Please sign in to comment.