multi_map/lib.rs
1//! # multi-map
2//!
3//! `MultiMap` is like a `std::collection::HashMap`, but allows you to use either of
4//! two different keys to retrieve items.
5//!
6//! The keys have two distinct types - `K1` and `K2` - which may be the same.
7//! Accessing on the primary `K1` key is via the usual `get`, `get_mut` and
8//! `remove_alt` methods, while accessing via the secondary `K2` key is via new
9//! `get_alt`, `get_mut_alt` and `remove_alt` methods. The value is of type `V`.
10//!
11//! Internally, two `HashMap`s are created - a main one on `<K1, (K2,
12//! V)>` and a second one on `<K2, K1>`. The `(K2, V)` tuple is so
13//! that when an item is removed using the `K1` key, the appropriate `K2`
14//! value is available so the `K2->K1` map can be removed from the second
15//! `MultiMap`, to keep them in sync.
16//!
17//! Using two `HashMap`s instead of one naturally brings a slight performance
18//! and memory penalty. Notably, indexing by `K2` requires two `HashMap` lookups.
19//!
20//! ```
21//! extern crate multi_map;
22//! use multi_map::MultiMap;
23//!
24//! # fn main() {
25//! #[derive(Hash,Clone,PartialEq,Eq)]
26//! enum ThingIndex {
27//! IndexOne,
28//! IndexTwo,
29//! IndexThree,
30//! };
31//!
32//! let mut map = MultiMap::new();
33//! map.insert(1, ThingIndex::IndexOne, "Chicken Fried Steak");
34//! map.insert(2, ThingIndex::IndexTwo, "Blueberry Pancakes");
35//!
36//! assert!(*map.get_alt(&ThingIndex::IndexOne).unwrap() == "Chicken Fried Steak");
37//! assert!(*map.get(&2).unwrap() == "Blueberry Pancakes");
38//! assert!(map.remove_alt(&ThingIndex::IndexTwo).unwrap() == "Blueberry Pancakes");
39//! # }
40//! ```
41
42use std::borrow::Borrow;
43use std::collections::hash_map;
44use std::collections::HashMap;
45use std::fmt::{self, Debug};
46use std::hash::Hash;
47
48#[derive(Eq)]
49pub struct MultiMap<K1: Eq + Hash, K2: Eq + Hash, V> {
50 value_map: HashMap<K1, (K2, V)>,
51 key_map: HashMap<K2, K1>,
52}
53
54impl<K1: Eq + Hash + Clone, K2: Eq + Hash + Clone, V> MultiMap<K1, K2, V> {
55 /// Creates a new MultiMap. The primary key is of type `K1` and the
56 /// secondary key is of type `K2`. The value is of type `V`. This is as
57 /// compared to a `std::collections::HashMap` which is typed on just `K` and
58 /// `V`.
59 ///
60 /// Internally, two HashMaps are created - a main one on `<K1, (K2,
61 /// V)>` and a second one on `<K2, K1>`. The `(K2, V)` tuple is so
62 /// that when an item is removed using the `K1` key, the appropriate `K2`
63 /// value is available so the `K2->K1` map can be removed from the second
64 /// HashMap, to keep them in sync.
65 pub fn new() -> MultiMap<K1, K2, V> {
66 MultiMap {
67 value_map: HashMap::new(),
68 key_map: HashMap::new(),
69 }
70 }
71
72 /// Creates an empty MultiMap with the specified capacity.
73 ///
74 /// The multi map will be able to hold at least `capacity` elements without reallocating. If `capacity` is 0, the multi map will not allocate.
75 pub fn with_capacity(capacity: usize) -> MultiMap<K1, K2, V> {
76 MultiMap {
77 value_map: HashMap::with_capacity(capacity),
78 key_map: HashMap::with_capacity(capacity),
79 }
80 }
81
82 /// Insert an item into the MultiMap. You must supply both keys to insert
83 /// an item. The keys cannot be modified at a later date, so if you only
84 /// have one key at this time, use a placeholder value for the second key
85 /// (perhaps `K2` is `Option<...>`) and remove then re-insert when the
86 /// second key becomes available.
87 pub fn insert(&mut self, key_one: K1, key_two: K2, value: V) {
88 self.key_map.insert(key_two.clone(), key_one.clone());
89 self.value_map.insert(key_one, (key_two, value));
90 }
91
92 /// Obtain a reference to an item in the MultiMap using the primary key,
93 /// just like a HashMap.
94 pub fn get(&self, key: &K1) -> Option<&V> {
95 let mut result = None;
96 if let Some(pair) = self.value_map.get(key) {
97 result = Some(&pair.1)
98 }
99 result
100 }
101
102 /// Obtain a mutable reference to an item in the MultiMap using the
103 /// primary key, just like a HashMap.
104 pub fn get_mut(&mut self, key: &K1) -> Option<&mut V> {
105 let mut result = None;
106 if let Some(pair) = self.value_map.get_mut(key) {
107 result = Some(&mut pair.1)
108 }
109 result
110 }
111
112 /// Obtain a reference to an item in the MultiMap using the secondary key.
113 /// Ordinary HashMaps can't do this.
114 pub fn get_alt(&self, key: &K2) -> Option<&V> {
115 let mut result = None;
116 if let Some(key_a) = self.key_map.get(key) {
117 if let Some(pair) = self.value_map.get(key_a) {
118 result = Some(&pair.1)
119 }
120 }
121 result
122 }
123
124 /// Obtain a mutable reference to an item in the MultiMap using the
125 /// secondary key. Ordinary HashMaps can't do this.
126 pub fn get_mut_alt(&mut self, key: &K2) -> Option<&mut V> {
127 let mut result = None;
128 if let Some(key_a) = self.key_map.get(key) {
129 if let Some(pair) = self.value_map.get_mut(key_a) {
130 result = Some(&mut pair.1)
131 }
132 }
133 result
134 }
135
136 /// Remove an item from the HashMap using the primary key. The value for the
137 /// given key is returned (if it exists), just like a HashMap. This removes
138 /// an item from the main HashMap, and the second `<K2, K1>` HashMap.
139 pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
140 where
141 K1: Borrow<Q>,
142 Q: Hash + Eq,
143 {
144 let mut result = None;
145 if let Some(pair) = self.value_map.remove(key) {
146 self.key_map.remove(&pair.0);
147 result = Some(pair.1)
148 }
149 result
150 }
151
152 /// Returns true if the map contains a value for the specified key. The key may be any borrowed
153 /// form of the map's key type, but Hash and Eq on the borrowed form must match those for the
154 /// key type
155 ///
156 /// ## Example
157 /// ```
158 /// #[macro_use]
159 /// extern crate multi_map;
160 /// use multi_map::MultiMap;
161 /// # fn main() {
162 /// let map = multimap! {
163 /// 1, "One" => String::from("Eins"),
164 /// 2, "Two" => String::from("Zwei"),
165 /// 3, "Three" => String::from("Drei"),
166 /// };
167 /// assert!(map.contains_key(&1));
168 /// assert!(!map.contains_key(&4));
169 /// # }
170 /// ```
171 pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
172 where
173 K1: Borrow<Q>,
174 Q: Hash + Eq,
175 {
176 self.value_map.contains_key(key)
177 }
178
179 /// Returns true if the map contains a value for the specified alternative key. The key may be
180 /// any borrowed form of the map's key type, but Hash and Eq on the borrowed form must match
181 /// those for the key type
182 ///
183 /// ## Example
184 /// ```
185 /// #[macro_use]
186 /// extern crate multi_map;
187 /// use multi_map::MultiMap;
188 /// # fn main() {
189 /// let map = multimap! {
190 /// 1, "One" => String::from("Eins"),
191 /// 2, "Two" => String::from("Zwei"),
192 /// 3, "Three" => String::from("Drei"),
193 /// };
194 /// assert!(map.contains_key_alt(&"One"));
195 /// assert!(!map.contains_key_alt(&"Four"));
196 /// # }
197 /// ```
198 pub fn contains_key_alt<Q: ?Sized>(&self, key: &Q) -> bool
199 where
200 K2: Borrow<Q>,
201 Q: Hash + Eq,
202 {
203 self.key_map.contains_key(key)
204 }
205
206 /// Remove an item from the HashMap using the secondary key. The value for
207 /// the given key is returned (if it exists). Ordinary HashMaps can't do
208 /// this. This removes an item from both the main HashMap and the second
209 /// `<K2, K1>` HashMap.
210 pub fn remove_alt<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
211 where
212 K2: Borrow<Q>,
213 Q: Hash + Eq,
214 {
215 let mut result = None;
216 if let Some(key_a) = self.key_map.remove(key) {
217 if let Some(pair) = self.value_map.remove(&key_a) {
218 result = Some(pair.1)
219 }
220 }
221 result
222 }
223
224 /// Iterate through all the values in the MultiMap in random order.
225 /// Note that the values
226 /// are `(K2, V)` tuples, not `V`, as you would get with a HashMap.
227 pub fn iter(&self) -> Iter<'_, K1, K2, V> {
228 Iter {
229 base: self.value_map.iter(),
230 }
231 }
232}
233
234impl<K1: Eq + Hash, K2: Eq + Hash, V: Eq> PartialEq for MultiMap<K1, K2, V> {
235 fn eq(&self, other: &MultiMap<K1, K2, V>) -> bool {
236 self.value_map.eq(&other.value_map)
237 }
238}
239
240impl<K1: Eq + Hash + Debug, K2: Eq + Hash + Debug, V: Debug> fmt::Debug for MultiMap<K1, K2, V> {
241 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
242 f.debug_map()
243 .entries(
244 self.value_map
245 .iter()
246 .map(|(key_one, &(ref key_two, ref value))| ((key_one, key_two), value)),
247 )
248 .finish()
249 }
250}
251
252impl<K1, K2, V> Default for MultiMap<K1, K2, V>
253where
254 K1: Eq + Hash + Clone,
255 K2: Eq + Hash + Clone,
256{
257 /// Creates an empty `MultiMap<K1, K2, V>`
258 #[inline]
259 fn default() -> MultiMap<K1, K2, V> {
260 MultiMap::new()
261 }
262}
263
264/// An iterator over the entries of a `MultiMap` like in a `HashMap` but with
265/// values of the form (K2, V) instead of V.
266///
267///
268/// This `struct` is created by the [`iter`] method on [`MultiMap`]. See its
269/// documentation for more.
270///
271#[derive(Clone, Debug)]
272pub struct Iter<'a, K1: 'a, K2: 'a, V: 'a> {
273 base: hash_map::Iter<'a, K1, (K2, V)>,
274}
275
276/// An owning iterator over the entries of a `MultiMap`.
277///
278/// This `struct` is created by the [`into_iter`] method on [`MultiMap`]
279/// (provided by the `IntoIterator` trait). See its documentation for more.
280///
281pub struct IntoIter<K1, K2, V> {
282 base: hash_map::IntoIter<K1, (K2, V)>,
283}
284// TODO: `HashMap` also implements this, do we need this as well?
285// impl<K, V> IntoIter<K, V> {
286// /// Returns a iterator of references over the remaining items.
287// #[inline]
288// pub(super) fn iter(&self) -> Iter<'_, K, V> {
289// Iter { base: self.base.rustc_iter() }
290// }
291// }
292
293impl<K1, K2, V> IntoIterator for MultiMap<K1, K2, V>
294where
295 K1: Eq + Hash + Debug,
296 K2: Eq + Hash + Debug,
297 V: Debug,
298{
299 type Item = (K1, (K2, V));
300 type IntoIter = IntoIter<K1, K2, V>;
301
302 /// Creates a consuming iterator, that is, one that moves each key-value
303 /// pair out of the map in arbitrary order. The map cannot be used after
304 /// calling this.
305 ///
306 fn into_iter(self) -> IntoIter<K1, K2, V> {
307 IntoIter {
308 base: self.value_map.into_iter(),
309 }
310 }
311}
312
313impl<'a, K1, K2, V> IntoIterator for &'a MultiMap<K1, K2, V>
314where
315 K1: Eq + Hash + Debug + Clone,
316 K2: Eq + Hash + Debug + Clone,
317 V: Debug,
318{
319 type Item = (&'a K1, &'a (K2, V));
320 type IntoIter = Iter<'a, K1, K2, V>;
321
322 fn into_iter(self) -> Iter<'a, K1, K2, V> {
323 self.iter()
324 }
325}
326
327impl<'a, K1, K2, V> Iterator for Iter<'a, K1, K2, V> {
328 type Item = (&'a K1, &'a (K2, V));
329
330 fn next(&mut self) -> Option<(&'a K1, &'a (K2, V))> {
331 self.base.next()
332 }
333 #[inline]
334 fn size_hint(&self) -> (usize, Option<usize>) {
335 self.base.size_hint()
336 }
337}
338
339impl<K1, K2, V> Iterator for IntoIter<K1, K2, V> {
340 type Item = (K1, (K2, V));
341
342 #[inline]
343 fn next(&mut self) -> Option<(K1, (K2, V))> {
344 self.base.next()
345 }
346 #[inline]
347 fn size_hint(&self) -> (usize, Option<usize>) {
348 self.base.size_hint()
349 }
350}
351
352#[macro_export]
353/// Create a `MultiMap` from a list of key-value tuples
354///
355/// ## Example
356///
357/// ```
358/// #[macro_use]
359/// extern crate multi_map;
360/// use multi_map::MultiMap;
361///
362/// # fn main() {
363/// #[derive(Hash,Clone,PartialEq,Eq)]
364/// enum ThingIndex {
365/// IndexOne,
366/// IndexTwo,
367/// IndexThree,
368/// };
369///
370/// let map = multimap!{
371/// 1, ThingIndex::IndexOne => "Chicken Fried Steak",
372/// 2, ThingIndex::IndexTwo => "Blueberry Pancakes",
373/// };
374///
375/// assert!(*map.get_alt(&ThingIndex::IndexOne).unwrap() == "Chicken Fried Steak");
376/// assert!(*map.get(&2).unwrap() == "Blueberry Pancakes");
377/// # }
378/// ```
379macro_rules! multimap {
380 (@single $($x:tt)*) => (());
381 (@count $($rest:expr),*) => (<[()]>::len(&[$(multimap!(@single $rest)),*]));
382
383 ($($key1:expr, $key2:expr => $value:expr,)+) => { multimap!($($key1, $key2 => $value),+) };
384 ($($key1:expr, $key2:expr => $value:expr),*) => {
385 {
386 let _cap = multimap!(@count $($key1),*);
387 let mut _map = MultiMap::with_capacity(_cap);
388 $(
389 _map.insert($key1, $key2, $value);
390 )*
391 _map
392 }
393 };
394}
395
396mod test {
397
398 #[test]
399 fn big_test() {
400 use MultiMap;
401
402 let mut map = MultiMap::new();
403
404 map.insert(1, "One", String::from("Ein"));
405 map.insert(2, "Two", String::from("Zwei"));
406 map.insert(3, "Three", String::from("Drei"));
407
408 assert!(*map.get(&1).unwrap() == String::from("Ein"));
409 assert!(*map.get(&2).unwrap() == String::from("Zwei"));
410 assert!(*map.get(&3).unwrap() == String::from("Drei"));
411 assert!(map.contains_key(&1));
412 assert!(!map.contains_key(&4));
413 assert!(map.contains_key_alt(&"One"));
414 assert!(!map.contains_key_alt(&"Four"));
415
416 map.get_mut_alt(&"One").unwrap().push_str("s");
417
418 assert!(*map.get_alt(&"One").unwrap() == String::from("Eins"));
419 assert!(*map.get_alt(&"Two").unwrap() == String::from("Zwei"));
420 assert!(*map.get_alt(&"Three").unwrap() == String::from("Drei"));
421
422 map.remove(&3);
423
424 assert!(*map.get_alt(&"One").unwrap() == String::from("Eins"));
425 assert!(*map.get_alt(&"Two").unwrap() == String::from("Zwei"));
426 assert!(map.get_alt(&"Three") == None);
427 assert!(map.get(&3) == None);
428
429 assert!(map.remove_alt(&"Three") == None);
430 assert!(*map.remove_alt(&"One").unwrap() == String::from("Eins"));
431
432 map.get_mut(&2).unwrap().push_str("!");
433
434 assert!(map.get(&1) == None);
435 assert!(*map.get(&2).unwrap() == String::from("Zwei!"));
436 assert!(map.get_alt(&"Three") == None);
437 assert!(map.get(&3) == None);
438 }
439 #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
440 struct MultiCount<'a>(i32, &'a str, &'a str);
441 #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
442 struct MultiCountOwned(i32, String, String);
443
444 #[test]
445 fn into_iter_test() {
446 use MultiMap;
447 let mut map = MultiMap::new();
448
449 map.insert(1, "One", String::from("Eins"));
450 map.insert(2, "Two", String::from("Zwei"));
451 map.insert(3, "Three", String::from("Drei"));
452
453 let mut vec_borrow = Vec::new();
454 for (k1, (k2, v)) in &map {
455 vec_borrow.push(MultiCount(*k1, *k2, v));
456 }
457 vec_borrow.sort();
458 assert_eq!(
459 vec_borrow,
460 vec!(
461 MultiCount(1, "One", "Eins"),
462 MultiCount(2, "Two", "Zwei"),
463 MultiCount(3, "Three", "Drei")
464 )
465 );
466
467 let mut vec_owned = Vec::new();
468 for (k1, (k2, v)) in map {
469 vec_owned.push(MultiCountOwned(k1, String::from(k2), v));
470 }
471 vec_owned.sort();
472 assert_eq!(
473 vec_owned,
474 vec!(
475 MultiCountOwned(1, String::from("One"), String::from("Eins")),
476 MultiCountOwned(2, String::from("Two"), String::from("Zwei")),
477 MultiCountOwned(3, String::from("Three"), String::from("Drei"))
478 )
479 )
480 }
481
482 #[test]
483 fn macro_test() {
484 use MultiMap;
485
486 let map: MultiMap<i32, &str, String> = MultiMap::new();
487
488 assert_eq!(map, multimap! {});
489
490 let mut map = MultiMap::new();
491 map.insert(1, "One", String::from("Eins"));
492
493 assert_eq!(
494 map,
495 multimap! {
496 1, "One" => String::from("Eins"),
497 }
498 );
499
500 assert_eq!(
501 map,
502 multimap! {
503 1, "One" => String::from("Eins")
504 }
505 );
506
507 let mut map = MultiMap::new();
508 map.insert(1, "One", String::from("Eins"));
509 map.insert(2, "Two", String::from("Zwei"));
510 map.insert(3, "Three", String::from("Drei"));
511
512 assert_eq!(
513 map,
514 multimap! {
515 1, "One" => String::from("Eins"),
516 2, "Two" => String::from("Zwei"),
517 3, "Three" => String::from("Drei"),
518 }
519 );
520
521 assert_eq!(
522 map,
523 multimap! {
524 1, "One" => String::from("Eins"),
525 2, "Two" => String::from("Zwei"),
526 3, "Three" => String::from("Drei")
527 }
528 );
529 }
530}