hirofa_utils/
auto_id_map.rs1use rand::{thread_rng, Rng};
2use std::collections::HashMap;
3
4pub struct AutoIdMap<T> {
19 max_size: usize,
20 pub map: HashMap<usize, T>,
21}
22
23impl<T> AutoIdMap<T> {
24 pub fn new() -> AutoIdMap<T> {
26 Self::new_with_max_size(usize::MAX)
27 }
28
29 pub fn new_with_max_size(max_size: usize) -> AutoIdMap<T> {
30 AutoIdMap {
31 max_size,
32 map: HashMap::new(),
33 }
34 }
35
36 pub fn foreach_value<F: Fn(&T)>(&self, f: F) {
37 for i in self.map.values() {
38 f(i);
39 }
40 }
41
42 pub fn foreach_value_mut<F: Fn(&mut T)>(&mut self, f: F) {
43 for i in self.map.values_mut() {
44 f(i);
45 }
46 }
47
48 pub fn foreach<F: Fn(&usize, &T)>(&self, f: F) {
49 for i in &self.map {
50 f(i.0, i.1);
51 }
52 }
53
54 pub fn clear(&mut self) {
55 self.map.clear();
56 }
57
58 pub fn remove_values<F: Fn(&T) -> bool>(&mut self, f: F) -> Vec<T> {
59 let mut rems = vec![];
60 let mut rem_keys = vec![];
61 {
62 for i in self.map.iter() {
63 if f(i.1) {
64 rem_keys.push(*i.0);
65 }
66 }
67 }
68 for k in rem_keys {
69 rems.push(self.map.remove(&k).unwrap());
70 }
71 rems
72 }
73
74 pub fn contains_value<F: Fn(&T) -> bool>(&self, f: F) -> bool {
75 for v in self.map.values() {
76 if f(v) {
77 return true;
78 }
79 }
80 false
81 }
82
83 pub fn insert(&mut self, elem: T) -> usize {
85 self.try_insert(elem).expect("map is full")
86 }
87
88 pub fn try_insert(&mut self, elem: T) -> Result<usize, &str> {
90 if self.map.len() >= self.max_size {
91 Err("AutoIdMap is full")
92 } else {
93 let mut id = thread_rng().gen_range(0..self.max_size);
94
95 while self.map.contains_key(&id) {
96 if id >= self.max_size - 1 {
97 id = 0;
98 } else {
99 id += 1;
100 }
101 }
102
103 self.map.insert(id, elem);
104 Ok(id)
105 }
106 }
107
108 #[allow(clippy::trivially_copy_pass_by_ref)]
110 pub fn replace(&mut self, id: &usize, elem: T) {
111 if !self.contains_key(id) {
113 panic!("no entry to replace for {}", id);
114 }
115 self.map.insert(*id, elem);
116 }
117
118 #[allow(clippy::trivially_copy_pass_by_ref)]
120 pub fn get(&self, id: &usize) -> Option<&T> {
121 self.map.get(id)
122 }
123
124 #[allow(clippy::trivially_copy_pass_by_ref)]
126 pub fn get_mut(&mut self, id: &usize) -> Option<&mut T> {
127 self.map.get_mut(id)
128 }
129
130 #[allow(clippy::trivially_copy_pass_by_ref)]
132 pub fn remove(&mut self, id: &usize) -> T {
133 self.map.remove(id).expect("no such elem")
134 }
135
136 #[allow(clippy::trivially_copy_pass_by_ref)]
138 pub fn remove_opt(&mut self, id: &usize) -> Option<T> {
139 self.map.remove(id)
140 }
141
142 #[allow(dead_code)]
144 pub fn len(&self) -> usize {
145 self.map.len()
146 }
147
148 #[allow(dead_code)]
150 pub fn is_empty(&self) -> bool {
151 self.map.is_empty()
152 }
153
154 #[allow(clippy::trivially_copy_pass_by_ref)]
156 pub fn contains_key(&self, id: &usize) -> bool {
157 self.map.contains_key(id)
158 }
159}
160
161impl<T> Default for AutoIdMap<T> {
162 fn default() -> Self {
163 AutoIdMap::new()
164 }
165}
166
167#[cfg(test)]
168pub mod tests {
169 use crate::auto_id_map::AutoIdMap;
170
171 #[test]
172 fn test_aim() {
173 let mut map = AutoIdMap::new_with_max_size(8);
174 for _x in 0..8 {
175 map.insert("foo");
176 }
177 assert_eq!(map.len(), 8);
178 map.remove(&5);
179 let free_id = map.insert("fail?");
180
181 assert_eq!(free_id, 5);
182 }
183
184 #[test]
185 fn test_aim_ms() {
186 let mut map = AutoIdMap::new_with_max_size(8);
187 for _x in 0..8 {
188 map.insert("foo");
189 }
190 assert_eq!(map.len(), 8);
191 map.remove(&5);
192 let free_id = map.insert("fail?");
193
194 assert_eq!(free_id, 5);
195
196 let res = map.try_insert("foobar");
197 assert!(res.is_err());
199 }
200}