1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
extern crate fxhash;
use std::hash::Hash;
use std::borrow::Borrow;

#[derive(Debug, Copy, Clone)]
pub struct Map<'a, K: 'a, V: 'a> {
    #[doc(hidden)]
    pub hashes: &'a [usize],

    #[doc(hidden)]
    pub entries: &'a [(K, V)],
}

impl<'a, K, V> Map<'a, K, V>
    where K: Hash + Eq
{
    #[inline]
    pub fn len(&self) -> usize {
        self.entries.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.entries.len() == 0
    }

    #[inline]
    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&'a V>
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        self.get_entry(key).map(|(_, v)| v)
    }

    #[inline]
    pub fn get_entry<Q: ?Sized>(&self, key: &Q) -> Option<(&'a K, &'a V)>
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        assert!(self.entries.len().is_power_of_two(),
                "Invalid StaticMap.  The pool must be a power of two.");
        assert!(self.entries.len() >= 16,
                "Invalid StaticMap.  The pool must have size >= 16.");

        // The mask yields the number of trailing bits of a
        // hash key which yeilds its ideal position.
        let mask = self.len() - 1;
        let hash = Self::hash(key);

        let mut pos = hash & mask;
        let mut dist = 0;

        loop {
            let entry_hash = self.hashes[pos];

            // Hash match found
            if entry_hash == hash {
                let entry = &self.entries[pos];
                if key.eq(entry.0.borrow()) {
                    return Some((&entry.0, &entry.1));
                }
            }

            // A zero hash indicates vacent bin
            if entry_hash == 0 {
                return None;
            }

            // The trailing bits of a hash indicates the position
            // the hash is stored.  Taking the difference between
            // the current hash value and the position will yield
            // the distance from the current key and it's ideal
            // location.  If the current key's distance from ideal
            // is greater than distance from our key's ideal then
            // we know there is no match.  This is the key
            // characteristic of Robin-Hood hashing.
            let entry_dist = pos.wrapping_sub(entry_hash) & mask;
            if dist > entry_dist {
                return None;
            }

            pos = pos.wrapping_add(1) & mask;
            dist += 1;
        }
    }

    #[inline]
    pub fn entries(&self) -> Entries<'a, K, V> {
        Entries {
            cursor: 0,
            hashes: self.hashes,
            entries: self.entries,
        }
    }

    #[inline]
    pub fn keys(&self) -> Keys<'a, K, V> {
        Keys { entries: self.entries() }
    }

    #[inline]
    pub fn values(&self) -> Values<'a, K, V> {
        Values { entries: self.entries() }
    }

    #[inline]
    pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        self.get_entry(key).is_some()
    }

    #[inline]
    fn hash<Q: ?Sized>(key: &Q) -> usize
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        fxhash::hash(key) as usize | 1
    }
}

pub struct Entries<'a, K: 'a, V: 'a> {
    cursor: usize,
    hashes: &'a [usize],
    entries: &'a [(K, V)],
}

impl<'a, K: 'a, V: 'a> Iterator for Entries<'a, K, V> {
    type Item = &'a (K, V);
    fn next(&mut self) -> Option<Self::Item> {
        while self.cursor < self.hashes.len() {
            if self.hashes[self.cursor] != 0 {
                let result = Some(&self.entries[self.cursor]);
                self.cursor += 1;
                return result;
            }
            self.cursor += 1
        }

        None
    }
}

pub struct Keys<'a, K: 'a, V: 'a> {
    entries: Entries<'a, K, V>,
}

impl<'a, K: 'a, V: 'a> Iterator for Keys<'a, K, V> {
    type Item = &'a K;
    fn next(&mut self) -> Option<Self::Item> {
        self.entries.next().map(|entry| &entry.0)
    }
}

pub struct Values<'a, K: 'a, V: 'a> {
    entries: Entries<'a, K, V>,
}

impl<'a, K: 'a, V: 'a> Iterator for Values<'a, K, V> {
    type Item = &'a V;
    fn next(&mut self) -> Option<Self::Item> {
        self.entries.next().map(|entry| &entry.1)
    }
}

impl<'a, K: 'a, V: 'a> IntoIterator for Map<'a, K, V>
    where K: Hash + Eq
{
    type Item = &'a (K, V);
    type IntoIter = Entries<'a, K, V>;
    fn into_iter(self) -> Entries<'a, K, V> {
        self.entries()
    }
}

#[macro_export]
macro_rules! static_map {
    (Default: $default:expr, $($key:expr => $value:expr),* $(,)*) => (
        static_map!(@stringify $default $(@ $key ? $value )*)
    );

    // This trick for stringifying into a procedural macro was
    // developed by dtolnay in the proc-macro-hack crate.
    (@stringify $($tt:tt)*) => ({
        #[derive(StaticMapMacro)]
        enum __StaticMap__ {
            A = static_map!(@zero $($tt)*)
        }

        __static_map__construct_map!()
    });

    (@zero $($tt:tt)*) => { 0 }
}