11//! # multi-map
22//!
3- //! MultiMap is like a std::collection::HashMap, but allows you to use either of
3+ //! ` MultiMap` is like a ` std::collection::HashMap` , but allows you to use either of
44//! two different keys to retrieve items.
55//!
66//! The keys have two distinct types - `K1` and `K2` - which may be the same.
77//! Accessing on the primary `K1` key is via the usual `get`, `get_mut` and
88//! `remove_alt` methods, while accessing via the secondary `K2` key is via new
99//! `get_alt`, `get_mut_alt` and `remove_alt` methods. The value is of type `V`.
1010//!
11- //! Internally, two HashMaps are created - a main one on `<K1, (K2,
11+ //! Internally, two `HashMap`s are created - a main one on `<K1, (K2,
1212//! V)>` and a second one on `<K2, K1>`. The `(K2, V)` tuple is so
1313//! that when an item is removed using the `K1` key, the appropriate `K2`
1414//! value is available so the `K2->K1` map can be removed from the second
15- //! HashMap , to keep them in sync.
15+ //! `MultiMap` , to keep them in sync.
1616//!
17- //! Using two HashMaps instead of one naturally brings a slight performance
18- //! and memory penalty. Notably, indexing by `K2` requires two HashMap lookups.
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.
1919//!
2020//! ```
21- //! # extern crate multi_map;
21+ //! extern crate multi_map;
2222//! use multi_map::MultiMap;
23+ //!
2324//! # fn main() {
2425//! #[derive(Hash,Clone,PartialEq,Eq)]
2526//! enum ThingIndex {
2627//! IndexOne,
2728//! IndexTwo,
2829//! IndexThree,
2930//! };
31+ //!
3032//! let mut map = MultiMap::new();
3133//! map.insert("One", ThingIndex::IndexOne, 1);
3234//! map.insert("Two", ThingIndex::IndexTwo, 2);
35+ //!
3336//! assert!(*map.get_alt(&ThingIndex::IndexOne).unwrap() == 1);
3437//! assert!(*map.get(&"Two").unwrap() == 2);
3538//! assert!(map.remove_alt(&ThingIndex::IndexTwo).unwrap() == 2);
@@ -40,7 +43,9 @@ use std::collections::HashMap;
4043use std:: collections:: hash_map:: Iter ;
4144use std:: hash:: Hash ;
4245use std:: borrow:: Borrow ;
46+ use std:: fmt:: { self , Debug } ;
4347
48+ #[ derive( Eq ) ]
4449pub struct MultiMap < K1 : Eq + Hash , K2 : Eq + Hash , V > {
4550 value_map : HashMap < K1 , ( K2 , V ) > ,
4651 key_map : HashMap < K2 , K1 > ,
@@ -64,6 +69,16 @@ impl<K1: Eq + Hash + Clone, K2: Eq + Hash + Clone, V> MultiMap<K1, K2, V> {
6469 }
6570 }
6671
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+
6782 /// Insert an item into the MultiMap. You must supply both keys to insert
6883 /// an item. The keys cannot be modified at a later date, so if you only
6984 /// have one key at this time, use a placeholder value for the second key
@@ -99,7 +114,7 @@ impl<K1: Eq + Hash + Clone, K2: Eq + Hash + Clone, V> MultiMap<K1, K2, V> {
99114 pub fn get_alt ( & self , key : & K2 ) -> Option < & V > {
100115 let mut result = None ;
101116 if let Some ( key_a) = self . key_map . get ( key) {
102- if let Some ( pair) = self . value_map . get ( & key_a) {
117+ if let Some ( pair) = self . value_map . get ( key_a) {
103118 result = Some ( & pair. 1 )
104119 }
105120 }
@@ -111,7 +126,7 @@ impl<K1: Eq + Hash + Clone, K2: Eq + Hash + Clone, V> MultiMap<K1, K2, V> {
111126 pub fn get_mut_alt ( & mut self , key : & K2 ) -> Option < & mut V > {
112127 let mut result = None ;
113128 if let Some ( key_a) = self . key_map . get ( key) {
114- if let Some ( pair) = self . value_map . get_mut ( & key_a) {
129+ if let Some ( pair) = self . value_map . get_mut ( key_a) {
115130 result = Some ( & mut pair. 1 )
116131 }
117132 }
@@ -157,6 +172,62 @@ impl<K1: Eq + Hash + Clone, K2: Eq + Hash + Clone, V> MultiMap<K1, K2, V> {
157172 }
158173}
159174
175+ impl < K1 : Eq + Hash , K2 : Eq + Hash , V : Eq > PartialEq for MultiMap < K1 , K2 , V > {
176+ fn eq ( & self , other : & MultiMap < K1 , K2 , V > ) -> bool {
177+ self . value_map . eq ( & other. value_map )
178+ }
179+ }
180+
181+ impl < K1 : Eq + Hash + Debug , K2 : Eq + Hash + Debug , V : Debug > fmt:: Debug for MultiMap < K1 , K2 , V > {
182+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
183+ f. debug_map ( ) . entries ( self . value_map . iter ( ) . map ( |( key_one, & ( ref key_two, ref value) ) | ( ( key_one, key_two) , value) ) ) . finish ( )
184+ }
185+ }
186+
187+ #[ macro_export]
188+ /// Create a `MultiMap` from a list of key-value tuples
189+ ///
190+ /// ## Example
191+ ///
192+ /// ```
193+ /// #[macro_use]
194+ /// extern crate multi_map;
195+ /// use multi_map::MultiMap;
196+ ///
197+ /// # fn main() {
198+ /// #[derive(Hash,Clone,PartialEq,Eq)]
199+ /// enum ThingIndex {
200+ /// IndexOne,
201+ /// IndexTwo,
202+ /// IndexThree,
203+ /// };
204+ ///
205+ /// let map = multimap!{
206+ /// "One", ThingIndex::IndexOne => 1,
207+ /// "Two", ThingIndex::IndexTwo => 2,
208+ /// };
209+ ///
210+ /// assert!(*map.get_alt(&ThingIndex::IndexOne).unwrap() == 1);
211+ /// assert!(*map.get(&"Two").unwrap() == 2);
212+ /// # }
213+ /// ```
214+ macro_rules! multimap {
215+ ( @single $( $x: tt) * ) => ( ( ) ) ;
216+ ( @count $( $rest: expr) ,* ) => ( <[ ( ) ] >:: len( & [ $( multimap!( @single $rest) ) ,* ] ) ) ;
217+
218+ ( $( $key1: expr, $key2: expr => $value: expr, ) +) => { multimap!( $( $key1, $key2 => $value) ,+) } ;
219+ ( $( $key1: expr, $key2: expr => $value: expr) ,* ) => {
220+ {
221+ let _cap = multimap!( @count $( $key1) ,* ) ;
222+ let mut _map = MultiMap :: with_capacity( _cap) ;
223+ $(
224+ _map. insert( $key1, $key2, $value) ;
225+ ) *
226+ _map
227+ }
228+ } ;
229+ }
230+
160231mod test {
161232
162233 #[ test]
@@ -195,6 +266,42 @@ mod test {
195266 assert ! ( * map. get( & 2 ) . unwrap( ) == String :: from( "Zwei!" ) ) ;
196267 assert ! ( map. get_alt( & "Three" ) == None ) ;
197268 assert ! ( map. get( & 3 ) == None ) ;
269+ }
270+
271+ #[ test]
272+ fn macro_test ( ) {
273+ use :: MultiMap ;
274+
275+ let map: MultiMap < i32 , & str , String > = MultiMap :: new ( ) ;
276+
277+ assert_eq ! ( map, multimap!{ } ) ;
278+
279+ let mut map = MultiMap :: new ( ) ;
280+ map. insert ( 1 , "One" , String :: from ( "Eins" ) ) ;
281+
282+ assert_eq ! ( map, multimap!{
283+ 1 , "One" => String :: from( "Eins" ) ,
284+ } ) ;
285+
286+ assert_eq ! ( map, multimap!{
287+ 1 , "One" => String :: from( "Eins" )
288+ } ) ;
289+
290+ let mut map = MultiMap :: new ( ) ;
291+ map. insert ( 1 , "One" , String :: from ( "Eins" ) ) ;
292+ map. insert ( 2 , "Two" , String :: from ( "Zwei" ) ) ;
293+ map. insert ( 3 , "Three" , String :: from ( "Drei" ) ) ;
294+
295+ assert_eq ! ( map, multimap!{
296+ 1 , "One" => String :: from( "Eins" ) ,
297+ 2 , "Two" => String :: from( "Zwei" ) ,
298+ 3 , "Three" => String :: from( "Drei" ) ,
299+ } ) ;
198300
301+ assert_eq ! ( map, multimap!{
302+ 1 , "One" => String :: from( "Eins" ) ,
303+ 2 , "Two" => String :: from( "Zwei" ) ,
304+ 3 , "Three" => String :: from( "Drei" )
305+ } ) ;
199306 }
200307}
0 commit comments