dedup iter adapter
This commit is contained in:
		
							parent
							
								
									15b8ec562c
								
							
						
					
					
						commit
						9511f49163
					
				|  | @ -16,3 +16,4 @@ pub mod v2_types; | ||||||
| 
 | 
 | ||||||
| pub mod any_type; | pub mod any_type; | ||||||
| pub mod types; | pub mod types; | ||||||
|  | pub mod util; | ||||||
|  |  | ||||||
							
								
								
									
										210
									
								
								unreal-sdk/src/util.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								unreal-sdk/src/util.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,210 @@ | ||||||
|  | use std::collections::hash_map::Entry; | ||||||
|  | use std::collections::HashMap; | ||||||
|  | use std::hash::Hash; | ||||||
|  | 
 | ||||||
|  | pub struct DedupIdentity; | ||||||
|  | 
 | ||||||
|  | pub trait DedupGetHash<T> { | ||||||
|  |     type Hashed: Hash + Eq; | ||||||
|  |     fn get_hash<'a>(&mut self, a: &'a T) -> Self::Hashed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> DedupGetHash<T> for DedupIdentity | ||||||
|  | where | ||||||
|  |     T: Hash + Eq + Clone, | ||||||
|  | { | ||||||
|  |     type Hashed = T; | ||||||
|  | 
 | ||||||
|  |     fn get_hash<'a>(&mut self, a: &'a T) -> Self::Hashed { | ||||||
|  |         a.clone() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<F, T, H> DedupGetHash<T> for F | ||||||
|  | where | ||||||
|  |     F: FnMut(&T) -> H, | ||||||
|  |     H: Hash + Eq, | ||||||
|  | { | ||||||
|  |     type Hashed = H; | ||||||
|  | 
 | ||||||
|  |     fn get_hash<'a>(&mut self, a: &'a T) -> Self::Hashed { | ||||||
|  |         self(a) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct DedupWithBy<I, F, H> | ||||||
|  | where | ||||||
|  |     I: Iterator, | ||||||
|  |     F: FnMut(usize, <I as Iterator>::Item) -> <I as Iterator>::Item, | ||||||
|  |     H: DedupGetHash<<I as Iterator>::Item>, | ||||||
|  | { | ||||||
|  |     iter: I, | ||||||
|  |     /// makes item unique, is told how many elements of this equality.
 | ||||||
|  |     cb_fn: F, | ||||||
|  |     /// returns the borrowed element by which to compare the iterators elements
 | ||||||
|  |     hash_fn: H, | ||||||
|  |     cache: HashMap<H::Hashed, usize>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub trait DedupIter: Iterator { | ||||||
|  |     fn dedup_with<'a, F>(self, f: F) -> DedupWithBy<Self, F, DedupIdentity> | ||||||
|  |     where | ||||||
|  |         F: FnMut(usize, <Self as Iterator>::Item) -> <Self as Iterator>::Item, | ||||||
|  |         Self: Sized, | ||||||
|  |         <Self as Iterator>::Item: Eq + Hash + Clone, | ||||||
|  |     { | ||||||
|  |         DedupWithBy { | ||||||
|  |             iter: self, | ||||||
|  |             cb_fn: f, | ||||||
|  |             hash_fn: DedupIdentity, | ||||||
|  |             cache: HashMap::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn dedup_with_by<'a, F, H>(self, f: F, h: H) -> DedupWithBy<Self, F, H> | ||||||
|  |     where | ||||||
|  |         F: FnMut(usize, <Self as Iterator>::Item) -> <Self as Iterator>::Item, | ||||||
|  |         H: DedupGetHash<<Self as Iterator>::Item>, | ||||||
|  |         Self: Sized, | ||||||
|  |     { | ||||||
|  |         DedupWithBy { | ||||||
|  |             iter: self, | ||||||
|  |             cb_fn: f, | ||||||
|  |             hash_fn: h, | ||||||
|  |             cache: HashMap::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<I> DedupIter for I where I: Iterator {} | ||||||
|  | 
 | ||||||
|  | impl<I, F, H> Iterator for DedupWithBy<I, F, H> | ||||||
|  | where | ||||||
|  |     I: Iterator, | ||||||
|  |     F: FnMut(usize, <I as Iterator>::Item) -> <I as Iterator>::Item, | ||||||
|  |     H: DedupGetHash<<I as Iterator>::Item>, | ||||||
|  | { | ||||||
|  |     type Item = <I as Iterator>::Item; | ||||||
|  | 
 | ||||||
|  |     fn next(&mut self) -> Option<Self::Item> { | ||||||
|  |         let mut next = self.iter.next()?; | ||||||
|  | 
 | ||||||
|  |         let next = loop { | ||||||
|  |             let hash = self.hash_fn.get_hash(&next); | ||||||
|  | 
 | ||||||
|  |             match self.cache.entry(hash) { | ||||||
|  |                 Entry::Occupied(mut entry) => { | ||||||
|  |                     *entry.get_mut() += 1; | ||||||
|  | 
 | ||||||
|  |                     next = (self.cb_fn)(*entry.get(), next); | ||||||
|  |                 } | ||||||
|  |                 Entry::Vacant(entry) => { | ||||||
|  |                     entry.insert(0); | ||||||
|  |                     break next; | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         Some(next) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn numbers() { | ||||||
|  |         let numbers = [1, 2, 2, 2, 3, 4, 5, 6, 22]; | ||||||
|  | 
 | ||||||
|  |         let unique = numbers | ||||||
|  |             .into_iter() | ||||||
|  |             .dedup_with(|n, i| (i * 10 + n) as usize) | ||||||
|  |             .collect::<Vec<_>>(); | ||||||
|  | 
 | ||||||
|  |         assert_eq!(&unique, &[1, 2, 21, 22, 3, 4, 5, 6, 221]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[derive(Debug, PartialEq, Clone)] | ||||||
|  |     struct Key { | ||||||
|  |         number: usize, | ||||||
|  |         other: f32, | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn keys() { | ||||||
|  |         let keys = [ | ||||||
|  |             Key { | ||||||
|  |                 number: 1, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 2, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 2, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 2, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 3, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 4, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 5, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |         ]; | ||||||
|  |         let expected = [ | ||||||
|  |             Key { | ||||||
|  |                 number: 1, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 2, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 21, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 22, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 3, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 4, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |             Key { | ||||||
|  |                 number: 5, | ||||||
|  |                 other: 1.0, | ||||||
|  |             }, | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         let unique = keys | ||||||
|  |             .into_iter() | ||||||
|  |             .dedup_with_by( | ||||||
|  |                 |n, key| Key { | ||||||
|  |                     number: (key.number * 10 + n), | ||||||
|  |                     ..key | ||||||
|  |                 }, | ||||||
|  |                 |key: &Key| -> usize { key.number }, | ||||||
|  |             ) | ||||||
|  |             .collect::<Vec<_>>(); | ||||||
|  | 
 | ||||||
|  |         assert_eq!(&unique, &expected); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
		Reference in a new issue