├── .gitignore ├── Cargo.toml ├── examples ├── std-1.rs ├── std-2.rs ├── std-3.rs └── std-4.rs └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hashmap" 3 | version = "0.1.0" 4 | authors = ["Jon Gjengset "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /examples/std-1.rs: -------------------------------------------------------------------------------- 1 | extern crate hashmap; 2 | use hashmap::HashMap; 3 | 4 | fn main() { 5 | // type inference lets us omit an explicit type signature (which 6 | // would be `HashMap<&str, &str>` in this example). 7 | let mut book_reviews = HashMap::new(); 8 | 9 | // review some books. 10 | book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); 11 | book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); 12 | book_reviews.insert("Pride and Prejudice", "Very enjoyable."); 13 | book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); 14 | 15 | // check for a specific one. 16 | if !book_reviews.contains_key("Les Misérables") { 17 | println!( 18 | "We've got {} reviews, but Les Misérables ain't one.", 19 | book_reviews.len() 20 | ); 21 | } 22 | 23 | // oops, this review has a lot of spelling mistakes, let's delete it. 24 | book_reviews.remove("The Adventures of Sherlock Holmes"); 25 | 26 | // look up the values associated with some keys. 27 | let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; 28 | for book in &to_find { 29 | match book_reviews.get(book) { 30 | Some(review) => println!("{}: {}", book, review), 31 | None => println!("{} is unreviewed.", book), 32 | } 33 | } 34 | 35 | // iterate over everything. 36 | for (book, review) in &book_reviews { 37 | println!("{}: \"{}\"", book, review); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/std-2.rs: -------------------------------------------------------------------------------- 1 | extern crate hashmap; 2 | use hashmap::HashMap; 3 | 4 | fn main() { 5 | // type inference lets us omit an explicit type signature (which 6 | // would be `HashMap<&str, u8>` in this example). 7 | let mut player_stats = HashMap::new(); 8 | 9 | fn random_stat_buff() -> u8 { 10 | // could actually return some random value here - let's just return 11 | // some fixed value for now 12 | 42 13 | } 14 | 15 | // insert a key only if it doesn't already exist 16 | player_stats.entry("health").or_insert(100); 17 | 18 | // insert a key using a function that provides a new value only if it 19 | // doesn't already exist 20 | player_stats 21 | .entry("defence") 22 | .or_insert_with(random_stat_buff); 23 | 24 | // update a key, guarding against the key possibly not being set 25 | let stat = player_stats.entry("attack").or_insert(100); 26 | *stat += random_stat_buff(); 27 | } 28 | -------------------------------------------------------------------------------- /examples/std-3.rs: -------------------------------------------------------------------------------- 1 | extern crate hashmap; 2 | use hashmap::HashMap; 3 | 4 | #[derive(Hash, Eq, PartialEq, Debug)] 5 | struct Viking { 6 | name: String, 7 | country: String, 8 | } 9 | 10 | impl Viking { 11 | /// Create a new Viking. 12 | fn new(name: &str, country: &str) -> Viking { 13 | Viking { 14 | name: name.to_string(), 15 | country: country.to_string(), 16 | } 17 | } 18 | } 19 | 20 | fn main() { 21 | // Use a HashMap to store the vikings' health points. 22 | let mut vikings = HashMap::new(); 23 | 24 | vikings.insert(Viking::new("Einar", "Norway"), 25); 25 | vikings.insert(Viking::new("Olaf", "Denmark"), 24); 26 | vikings.insert(Viking::new("Harald", "Iceland"), 12); 27 | 28 | // Use derived implementation to print the status of the vikings. 29 | for (viking, health) in &vikings { 30 | println!("{:?} has {} hp", viking, health); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/std-4.rs: -------------------------------------------------------------------------------- 1 | extern crate hashmap; 2 | use hashmap::HashMap; 3 | 4 | fn main() { 5 | let _timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] 6 | .iter() 7 | .cloned() 8 | .collect(); 9 | } 10 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Borrow; 2 | use std::collections::hash_map::DefaultHasher; 3 | use std::hash::{Hash, Hasher}; 4 | use std::mem; 5 | 6 | const INITIAL_NBUCKETS: usize = 1; 7 | 8 | pub struct HashMap { 9 | buckets: Vec>, 10 | items: usize, 11 | } 12 | 13 | impl HashMap { 14 | pub fn new() -> Self { 15 | HashMap { 16 | buckets: Vec::new(), 17 | items: 0, 18 | } 19 | } 20 | } 21 | 22 | pub struct OccupiedEntry<'a, K: 'a, V: 'a> { 23 | entry: &'a mut (K, V), 24 | } 25 | 26 | pub struct VacantEntry<'a, K: 'a, V: 'a> { 27 | key: K, 28 | map: &'a mut HashMap, 29 | bucket: usize, 30 | } 31 | 32 | impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { 33 | pub fn insert(self, value: V) -> &'a mut V 34 | where 35 | K: Hash + Eq, 36 | { 37 | self.map.buckets[self.bucket].push((self.key, value)); 38 | self.map.items += 1; 39 | &mut self.map.buckets[self.bucket].last_mut().unwrap().1 40 | } 41 | } 42 | 43 | pub enum Entry<'a, K: 'a, V: 'a> { 44 | Occupied(OccupiedEntry<'a, K, V>), 45 | Vacant(VacantEntry<'a, K, V>), 46 | } 47 | 48 | impl<'a, K, V> Entry<'a, K, V> 49 | where 50 | K: Hash + Eq, 51 | { 52 | pub fn or_insert(self, value: V) -> &'a mut V { 53 | match self { 54 | Entry::Occupied(e) => &mut e.entry.1, 55 | Entry::Vacant(e) => e.insert(value), 56 | } 57 | } 58 | 59 | pub fn or_insert_with(self, maker: F) -> &'a mut V 60 | where 61 | F: FnOnce() -> V, 62 | { 63 | match self { 64 | Entry::Occupied(e) => &mut e.entry.1, 65 | Entry::Vacant(e) => e.insert(maker()), 66 | } 67 | } 68 | 69 | pub fn or_default(self) -> &'a mut V 70 | where 71 | V: Default, 72 | { 73 | self.or_insert_with(Default::default) 74 | } 75 | } 76 | 77 | impl HashMap 78 | where 79 | K: Hash + Eq, 80 | { 81 | fn bucket(&self, key: &Q) -> Option 82 | where 83 | K: Borrow, 84 | Q: Hash + Eq + ?Sized, 85 | { 86 | if self.buckets.is_empty() { 87 | return None; 88 | } 89 | let mut hasher = DefaultHasher::new(); 90 | key.hash(&mut hasher); 91 | Some((hasher.finish() % self.buckets.len() as u64) as usize) 92 | } 93 | 94 | pub fn entry<'a>(&'a mut self, key: K) -> Entry<'a, K, V> { 95 | if self.buckets.is_empty() || self.items > 3 * self.buckets.len() / 4 { 96 | self.resize(); 97 | } 98 | 99 | let bucket = self.bucket(&key).expect("buckets.is_empty() handled above"); 100 | match self.buckets[bucket].iter().position(|&(ref ekey, _)| ekey == &key) { 101 | Some(index) => Entry::Occupied(OccupiedEntry { 102 | entry: &mut self.buckets[bucket][index] 103 | }), 104 | None => Entry::Vacant(VacantEntry { map: self, key, bucket }) 105 | } 106 | } 107 | 108 | pub fn insert(&mut self, key: K, value: V) -> Option { 109 | if self.buckets.is_empty() || self.items > 3 * self.buckets.len() / 4 { 110 | self.resize(); 111 | } 112 | 113 | let bucket = self.bucket(&key).expect("buckets.is_empty() handled above"); 114 | let bucket = &mut self.buckets[bucket]; 115 | 116 | for &mut (ref ekey, ref mut evalue) in bucket.iter_mut() { 117 | if ekey == &key { 118 | return Some(mem::replace(evalue, value)); 119 | } 120 | } 121 | 122 | self.items += 1; 123 | bucket.push((key, value)); 124 | None 125 | } 126 | 127 | pub fn get(&self, key: &Q) -> Option<&V> 128 | where 129 | K: Borrow, 130 | Q: Hash + Eq + ?Sized, 131 | { 132 | let bucket = self.bucket(key)?; 133 | self.buckets[bucket] 134 | .iter() 135 | .find(|&(ref ekey, _)| ekey.borrow() == key) 136 | .map(|&(_, ref v)| v) 137 | } 138 | 139 | pub fn contains_key(&self, key: &Q) -> bool 140 | where 141 | K: Borrow, 142 | Q: Hash + Eq + ?Sized, 143 | { 144 | self.get(key).is_some() 145 | } 146 | 147 | pub fn remove(&mut self, key: &Q) -> Option 148 | where 149 | K: Borrow, 150 | Q: Hash + Eq + ?Sized, 151 | { 152 | let bucket = self.bucket(key)?; 153 | let bucket = &mut self.buckets[bucket]; 154 | let i = bucket 155 | .iter() 156 | .position(|&(ref ekey, _)| ekey.borrow() == key)?; 157 | self.items -= 1; 158 | Some(bucket.swap_remove(i).1) 159 | } 160 | 161 | pub fn len(&self) -> usize { 162 | self.items 163 | } 164 | 165 | pub fn is_empty(&self) -> bool { 166 | self.items == 0 167 | } 168 | 169 | fn resize(&mut self) { 170 | let target_size = match self.buckets.len() { 171 | 0 => INITIAL_NBUCKETS, 172 | n => 2 * n, 173 | }; 174 | 175 | let mut new_buckets = Vec::with_capacity(target_size); 176 | new_buckets.extend((0..target_size).map(|_| Vec::new())); 177 | 178 | for (key, value) in self.buckets.iter_mut().flat_map(|bucket| bucket.drain(..)) { 179 | let mut hasher = DefaultHasher::new(); 180 | key.hash(&mut hasher); 181 | let bucket = (hasher.finish() % new_buckets.len() as u64) as usize; 182 | new_buckets[bucket].push((key, value)); 183 | } 184 | 185 | mem::replace(&mut self.buckets, new_buckets); 186 | } 187 | } 188 | 189 | pub struct Iter<'a, K: 'a, V: 'a> { 190 | map: &'a HashMap, 191 | bucket: usize, 192 | at: usize, 193 | } 194 | 195 | impl<'a, K, V> Iterator for Iter<'a, K, V> { 196 | type Item = (&'a K, &'a V); 197 | fn next(&mut self) -> Option { 198 | loop { 199 | match self.map.buckets.get(self.bucket) { 200 | Some(bucket) => { 201 | match bucket.get(self.at) { 202 | Some(&(ref k, ref v)) => { 203 | // move along self.at and self.bucket 204 | self.at += 1; 205 | break Some((k, v)); 206 | } 207 | None => { 208 | self.bucket += 1; 209 | self.at = 0; 210 | continue; 211 | } 212 | } 213 | } 214 | None => break None, 215 | } 216 | } 217 | } 218 | } 219 | 220 | impl<'a, K, V> IntoIterator for &'a HashMap { 221 | type Item = (&'a K, &'a V); 222 | type IntoIter = Iter<'a, K, V>; 223 | fn into_iter(self) -> Self::IntoIter { 224 | Iter { 225 | map: self, 226 | bucket: 0, 227 | at: 0, 228 | } 229 | } 230 | } 231 | 232 | pub struct IntoIter { 233 | map: HashMap, 234 | bucket: usize, 235 | } 236 | 237 | impl Iterator for IntoIter { 238 | type Item = (K, V); 239 | fn next(&mut self) -> Option { 240 | loop { 241 | match self.map.buckets.get_mut(self.bucket) { 242 | Some(bucket) => match bucket.pop() { 243 | Some(x) => break Some(x), 244 | None => { 245 | self.bucket += 1; 246 | continue; 247 | } 248 | }, 249 | None => break None, 250 | } 251 | } 252 | } 253 | } 254 | 255 | impl IntoIterator for HashMap { 256 | type Item = (K, V); 257 | type IntoIter = IntoIter; 258 | fn into_iter(self) -> Self::IntoIter { 259 | IntoIter { 260 | map: self, 261 | bucket: 0, 262 | } 263 | } 264 | } 265 | 266 | use std::iter::FromIterator; 267 | impl FromIterator<(K, V)> for HashMap 268 | where 269 | K: Hash + Eq, 270 | { 271 | fn from_iter(iter: I) -> Self 272 | where 273 | I: IntoIterator, 274 | { 275 | let mut map = HashMap::new(); 276 | for (k, v) in iter { 277 | map.insert(k, v); 278 | } 279 | map 280 | } 281 | } 282 | 283 | #[cfg(test)] 284 | mod tests { 285 | use super::*; 286 | 287 | #[test] 288 | fn insert() { 289 | let mut map = HashMap::new(); 290 | assert_eq!(map.len(), 0); 291 | assert!(map.is_empty()); 292 | map.insert("foo", 42); 293 | assert_eq!(map.len(), 1); 294 | assert!(!map.is_empty()); 295 | assert_eq!(map.get(&"foo"), Some(&42)); 296 | assert_eq!(map.remove(&"foo"), Some(42)); 297 | assert_eq!(map.len(), 0); 298 | assert!(map.is_empty()); 299 | assert_eq!(map.get(&"foo"), None); 300 | } 301 | 302 | #[test] 303 | fn iter() { 304 | let mut map = HashMap::new(); 305 | map.insert("foo", 42); 306 | map.insert("bar", 43); 307 | map.insert("baz", 142); 308 | map.insert("quox", 7); 309 | for (&k, &v) in &map { 310 | match k { 311 | "foo" => assert_eq!(v, 42), 312 | "bar" => assert_eq!(v, 43), 313 | "baz" => assert_eq!(v, 142), 314 | "quox" => assert_eq!(v, 7), 315 | _ => unreachable!(), 316 | } 317 | } 318 | assert_eq!((&map).into_iter().count(), 4); 319 | 320 | let mut items = 0; 321 | for (k, v) in map { 322 | match k { 323 | "foo" => assert_eq!(v, 42), 324 | "bar" => assert_eq!(v, 43), 325 | "baz" => assert_eq!(v, 142), 326 | "quox" => assert_eq!(v, 7), 327 | _ => unreachable!(), 328 | } 329 | items += 1; 330 | } 331 | assert_eq!(items, 4); 332 | } 333 | 334 | #[test] 335 | fn empty_hashmap() { 336 | let mut map = HashMap::<&str, &str>::new(); 337 | assert_eq!(map.contains_key("key"), false); 338 | assert_eq!(map.get("key"), None); 339 | assert_eq!(map.remove("key"), None); 340 | } 341 | } 342 | --------------------------------------------------------------------------------