Skip to content

Commit

Permalink
use fnv instead of SipHasher for HashMaps. add type FnvMap (#106)
Browse files Browse the repository at this point in the history
* use fnv instead of SipHasher for HashMaps. add type FnvMap

* refactor FnvMap to it's own module

* add comment to fnv module

* move comment
  • Loading branch information
leshow authored and Marwes committed Aug 10, 2016
1 parent 140d75d commit 4a64c68
Show file tree
Hide file tree
Showing 17 changed files with 78 additions and 59 deletions.
1 change: 1 addition & 0 deletions base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ documentation = "https://marwes.github.io/gluon/gluon/index.html"
[dependencies]
log = "0.3.6"
quick-error = "1.0.0"
fnv = "1.0.3"
6 changes: 3 additions & 3 deletions base/src/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
//! are alive. This is done by storing each value in a stable memory location and preventing an
//! earlier inserted value to be overwritten.
use std::cell::{RefCell, Ref};
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::iter::{FromIterator, IntoIterator};
use std::ops::{Index, IndexMut};

use fnv::FnvMap;
// NOTE: transmute is used to circumvent the borrow checker in this module
// This is safe since the containers hold boxed values meaning allocating larger
// storage does not invalidate the references that are handed out and because values
Expand All @@ -26,7 +26,7 @@ unsafe fn forget_lifetime_mut<'a, 'b, T: ?Sized>(x: &'a mut T) -> &'b mut T {
// Through this and the fact the all values are stored as pointers it is possible to safely
// insert new values without invalidating pointers retrieved from it
pub struct FixedMap<K, V> {
map: RefCell<HashMap<K, Box<V>>>,
map: RefCell<FnvMap<K, Box<V>>>,
}

impl<K: Eq + Hash, V> Default for FixedMap<K, V> {
Expand All @@ -43,7 +43,7 @@ impl<K: Eq + Hash + fmt::Debug, V: fmt::Debug> fmt::Debug for FixedMap<K, V> {

impl<K: Eq + Hash, V> FixedMap<K, V> {
pub fn new() -> FixedMap<K, V> {
FixedMap { map: RefCell::new(HashMap::new()) }
FixedMap { map: RefCell::new(FnvMap::default()) }
}

pub fn clear(&mut self) {
Expand Down
13 changes: 13 additions & 0 deletions base/src/fnv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
extern crate fnv;

use std::collections::HashMap;
use std::hash::BuildHasherDefault;

pub use self::fnv::FnvHasher;

/// Non-crypto HashMap using Fnv Hasher
///
/// The default hashing implementation in std::collections uses `SipHasher`
/// since gluon doesn't need the cryptographic quarantee provided by SipHasher,
/// we've opted for the faster fnv hash.
pub type FnvMap<K, V> = HashMap<K, V, BuildHasherDefault<FnvHasher>>;
6 changes: 3 additions & 3 deletions base/src/instantiate.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ops::Deref;

use types;
use types::{AliasData, Type, Generic, TcType, TypeEnv, merge};
use symbol::Symbol;
use fnv::FnvMap;

quick_error! {
#[derive(Debug)]
Expand Down Expand Up @@ -166,12 +166,12 @@ pub fn type_of_alias(alias: &AliasData<Symbol, TcType>, arguments: &[TcType]) ->

#[derive(Debug, Default)]
pub struct Instantiator {
pub named_variables: RefCell<HashMap<Symbol, TcType>>,
pub named_variables: RefCell<FnvMap<Symbol, TcType>>,
}

impl Instantiator {
pub fn new() -> Instantiator {
Instantiator { named_variables: RefCell::new(HashMap::new()) }
Instantiator { named_variables: RefCell::new(FnvMap::default()) }
}

fn variable_for(&self,
Expand Down
1 change: 1 addition & 0 deletions base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ pub mod types;
pub mod scoped_map;
pub mod metadata;
pub mod instantiate;
pub mod fnv;
7 changes: 4 additions & 3 deletions base/src/scoped_map.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//! A map data type which allows the same key to exist at multiple scope levels
use std::borrow::Borrow;
use std::collections::HashMap;
use std::collections::hash_map;
use std::collections::hash_map::{Entry, IterMut};
use std::hash::Hash;

use fnv::FnvMap;

/// A map struct which allows for the introduction of different scopes
/// Introducing a new scope will make it possible to introduce additional
/// variables with names already defined, shadowing the old name
Expand All @@ -13,7 +14,7 @@ use std::hash::Hash;
pub struct ScopedMap<K: Eq + Hash + Clone, V> {
/// A hashmap storing a key -> value mapping
/// Stores a vector of values in which the value at the top is value returned from 'get'
map: HashMap<K, Vec<V>>,
map: FnvMap<K, Vec<V>>,
/// A vector of scopes, when entering a scope, None is added as a marker
/// when later exiting a scope, values are removed from the map until the marker is found
scopes: Vec<Option<K>>,
Expand All @@ -23,7 +24,7 @@ pub struct ScopedMap<K: Eq + Hash + Clone, V> {
impl<K: Eq + Hash + Clone, V> ScopedMap<K, V> {
pub fn new() -> ScopedMap<K, V> {
ScopedMap {
map: HashMap::new(),
map: FnvMap::default(),
scopes: Vec::new(),
}
}
Expand Down
10 changes: 5 additions & 5 deletions base/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! Module which contains types working with symbols
use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::fmt;
use std::sync::Arc;
use std::borrow::Borrow;
use std::ops::Deref;

use ast::{AstId, DisplayEnv, IdentEnv, AstType};
use fnv::FnvMap;

// FIXME Don't have a double indirection (Arc + String)
#[derive(Clone, Eq)]
Expand Down Expand Up @@ -262,15 +262,15 @@ impl<'a> From<&'a Name> for NameBuf {

#[derive(Debug, Default)]
pub struct Symbols {
strings: HashMap<Symbol, NameBuf>,
indexes: HashMap<NameBuf, Symbol>,
strings: FnvMap<Symbol, NameBuf>,
indexes: FnvMap<NameBuf, Symbol>,
}

impl Symbols {
pub fn new() -> Symbols {
Symbols {
strings: HashMap::new(),
indexes: HashMap::new(),
strings: FnvMap::default(),
indexes: FnvMap::default(),
}
}

Expand Down
7 changes: 4 additions & 3 deletions check/src/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,16 +320,17 @@ pub fn rename(symbols: &mut SymbolModule,
}


use std::collections::HashMap;
use base::instantiate;
use unify_type::{TypeError, State};
use unify::{Error as UnifyError, Unifier, Unifiable, UnifierState};

use base::fnv::FnvMap;

pub fn equivalent(env: &TypeEnv, actual: &TcType, inferred: &TcType) -> bool {
let mut unifier = UnifierState {
state: State::new(env),
unifier: Equivalent {
map: HashMap::new(),
map: FnvMap::default(),
equiv: true,
},
};
Expand All @@ -338,7 +339,7 @@ pub fn equivalent(env: &TypeEnv, actual: &TcType, inferred: &TcType) -> bool {
}

struct Equivalent {
map: HashMap<Symbol, TcType>,
map: FnvMap<Symbol, TcType>,
equiv: bool,
}

Expand Down
7 changes: 3 additions & 4 deletions check/src/unify.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;

use base::error::Errors;

use base::fnv::FnvMap;
use substitution::{Substitution, Substitutable, Variable};

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -174,15 +173,15 @@ pub fn intersection<S, T>(subs: &Substitution<T>, state: S, l: &T, r: &T) -> T
let mut unifier = UnifierState {
state: state,
unifier: Intersect {
mismatch_map: HashMap::new(),
mismatch_map: FnvMap::default(),
subs: subs,
},
};
unifier.try_match(l, r).unwrap_or_else(|| l.clone())
}

struct Intersect<'m, T: 'm> {
mismatch_map: HashMap<(T, T), T>,
mismatch_map: FnvMap<(T, T), T>,
subs: &'m Substitution<T>,
}

Expand Down
7 changes: 3 additions & 4 deletions src/import.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Implementation of the `import` macro.
use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, RwLock, Mutex};
use std::fs::File;
use std::io;
Expand All @@ -15,7 +14,7 @@ use vm::thread::{Thread, ThreadInternal};
use vm::internal::Value;
use super::{filename_to_module, Compiler};
use base::types::TcIdent;

use base::fnv::FnvMap;

quick_error! {
/// Error type for the import macro
Expand Down Expand Up @@ -70,10 +69,10 @@ impl Importer for DefaultImporter {
}

#[derive(Clone)]
pub struct CheckImporter(pub Arc<Mutex<HashMap<String, ast::LExpr<ast::TcIdent<Symbol>>>>>);
pub struct CheckImporter(pub Arc<Mutex<FnvMap<String, ast::LExpr<ast::TcIdent<Symbol>>>>>);
impl CheckImporter {
pub fn new() -> CheckImporter {
CheckImporter(Arc::new(Mutex::new(HashMap::new())))
CheckImporter(Arc::new(Mutex::new(FnvMap::default())))
}
}
impl Importer for CheckImporter {
Expand Down
8 changes: 5 additions & 3 deletions vm/src/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ use std::fmt;
use std::mem;
use std::ptr;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque};
use std::collections::VecDeque;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::cell::Cell;
use std::any::{Any, TypeId};
use std::marker::PhantomData;

use base::fnv::FnvMap;

#[inline]
unsafe fn allocate(size: usize) -> *mut u8 {
// Allocate an extra element if it does not fit exactly
Expand Down Expand Up @@ -99,7 +101,7 @@ pub struct Gc {
values: Option<AllocPtr>,
allocated_memory: usize,
collect_limit: usize,
type_infos: HashMap<TypeId, Box<TypeInfo>>,
type_infos: FnvMap<TypeId, Box<TypeInfo>>,
/// The generation of a gc determines what values it needs to copy and what values it can
/// share. A gc can share values generated by itself (the same generation) and those in an
/// earlier (lower) generation. It is important to note that two garbage collectors can have
Expand Down Expand Up @@ -512,7 +514,7 @@ impl Gc {
values: None,
allocated_memory: 0,
collect_limit: 100,
type_infos: HashMap::new(),
type_infos: FnvMap::default(),
generation: generation,
}
}
Expand Down
6 changes: 3 additions & 3 deletions vm/src/interner.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::collections::HashMap;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use base::ast::{AstId, DisplayEnv, IdentEnv, AstType};
use base::fnv::FnvMap;

use gc::{GcPtr, Gc, Traverseable};
use array::Str;
Expand Down Expand Up @@ -56,7 +56,7 @@ pub struct Interner {
// not be expected to be the same as ordinary strings, we use a transmute to &'static str to
// have the keys as strings without any unsafety as the keys do not escape the interner and they
// live as long as their values
indexes: HashMap<&'static str, InternedStr>,
indexes: FnvMap<&'static str, InternedStr>,
}

impl Traverseable for Interner {
Expand All @@ -69,7 +69,7 @@ impl Traverseable for Interner {

impl Interner {
pub fn new() -> Interner {
Interner { indexes: HashMap::new() }
Interner { indexes: FnvMap::default() }
}

pub fn intern(&mut self, gc: &mut Gc, s: &str) -> InternedStr {
Expand Down
6 changes: 3 additions & 3 deletions vm/src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! Module providing the building blocks to create macros and expand them.
use std::sync::RwLock;
use std::collections::HashMap;
use std::error::Error as StdError;

use base::ast;
use base::ast::MutVisitor;
use base::types::TcIdent;
use base::error::Errors;
use base::fnv::FnvMap;

use thread::Thread;

Expand Down Expand Up @@ -41,13 +41,13 @@ impl<F: ::mopa::Any + Clone + Send + Sync> Macro for F
/// Type containing macros bound to symbols which can be applied on an AST expression to transform
/// it.
pub struct MacroEnv {
macros: RwLock<HashMap<String, Box<Macro>>>,
macros: RwLock<FnvMap<String, Box<Macro>>>,
}

impl MacroEnv {
/// Creates a new `MacroEnv`
pub fn new() -> MacroEnv {
MacroEnv { macros: RwLock::new(HashMap::new()) }
MacroEnv { macros: RwLock::new(FnvMap::default()) }
}

/// Inserts a `Macro` which acts on any occurance of `symbol` when applied to an expression.
Expand Down
4 changes: 2 additions & 2 deletions vm/src/thread.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! The thread/vm type
use std::any::Any;
use std::collections::HashMap;
use std::sync::{Mutex, RwLock, RwLockWriteGuard, RwLockReadGuard, MutexGuard};
use std::cmp::Ordering;
use std::fmt;
Expand All @@ -12,6 +11,7 @@ use base::metadata::Metadata;
use base::symbol::Symbol;
use base::types::TcType;
use base::types;
use base::fnv::FnvMap;

use {Variants, Error, Result};
use macros::MacroEnv;
Expand Down Expand Up @@ -676,7 +676,7 @@ impl ThreadInternal for Thread {
}

fn deep_clone(&self, value: Value) -> Result<Value> {
let mut visited = HashMap::new();
let mut visited = FnvMap::default();
::value::deep_clone(value, &mut visited, &mut self.local_gc.lock().unwrap())
}
}
Expand Down
10 changes: 5 additions & 5 deletions vm/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use base::symbol::{Symbol, SymbolRef};
use base::types;
use base::types::{Alias, KindEnv, TypeEnv, TcType, Type};
use base::fnv::FnvMap;

pub use self::Instruction::*;

Expand Down Expand Up @@ -139,8 +139,8 @@ impl Instruction {

#[derive(Debug)]
pub struct TypeInfos {
pub id_to_type: HashMap<String, Alias<Symbol, TcType>>,
pub type_to_id: HashMap<TcType, TcType>,
pub id_to_type: FnvMap<String, Alias<Symbol, TcType>>,
pub type_to_id: FnvMap<TcType, TcType>,
}

impl KindEnv for TypeInfos {
Expand Down Expand Up @@ -209,8 +209,8 @@ impl TypeEnv for TypeInfos {
impl TypeInfos {
pub fn new() -> TypeInfos {
TypeInfos {
id_to_type: HashMap::new(),
type_to_id: HashMap::new(),
id_to_type: FnvMap::default(),
type_to_id: FnvMap::default(),
}
}

Expand Down
Loading

0 comments on commit 4a64c68

Please sign in to comment.