ordered_hash_map/set.rs
1use core::borrow::Borrow;
2use core::fmt;
3use core::hash::{BuildHasher, Hash};
4use core::ops::Index;
5
6pub use hashbrown::DefaultHashBuilder;
7pub use hashbrown::TryReserveError;
8
9use crate::ordered_map;
10
11mod iter;
12pub use iter::{Drain, IntoIter, Iter};
13
14#[cfg(feature = "serde")]
15mod serde;
16
17/// A hash set which preserves the order of insertion.
18///
19/// Backed by [`hashbrown`] and its default hashing algorithm, currently [`AHash`]. The hashing
20/// algorithm can be changed on a per-map basis with [`with_hasher`] and [`with_capacity_and_hasher`].
21/// More details on hashing algorithms and why AHash was selected in the [`hashbrown`] crate.
22///
23/// To switch to the same hasher as [`HashMap`] use [`RandomState`]. This will switch to SipHash, a
24/// HashDos resistant algorithm but it may be slower in some cases.
25///
26/// Being backed by a HashMap, this container has all the same requirements on its keys as
27/// [`HashMap`]. Specifically, Keys must implement [`Eq`] and [`Hash`]. You can typically derive
28/// these for types with `#[derive(PartialEq, Eq, hash)]`. If you implement these yourself you must
29/// ensure the following holds:
30///
31/// ```text
32/// k1 == k2 -> hash(k1) == hash(k2)
33/// ```
34/// You are also responsible to ensure Keys do not mutate such that their hash can change while in
35/// the map. For more information, check [`HashMap`].
36///
37/// This container has some additional memory overhead on top of its backing HashMap. [`OrderedHashSet`]
38/// holds two pointers to maintain the linked list. Each Value inserted has the overhead of three pointers, one for the key
39/// and two for the linked list properties.
40///
41/// [`AHash`]: https://crates.io/crates/ahash
42/// [`hashbrown`]: https://crates.io/crates/hashbrown
43/// [`with_hasher`]: Self::with_hasher
44/// [`with_capacity_and_hasher`]: Self::with_capacity_and_hasher
45/// [`HashMap`]: std::collections::HashMap
46/// [`RandomState`]: std::collections::hash_map::RandomState
47pub struct OrderedHashSet<T, S = DefaultHashBuilder> {
48 map: ordered_map::OrderedHashMap<T, (), S>,
49}
50
51impl<T, S> fmt::Debug for OrderedHashSet<T, S>
52where
53 T: fmt::Debug,
54{
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 f.debug_list().entries(self.iter()).finish()
57 }
58}
59
60impl<T, S> Clone for OrderedHashSet<T, S>
61where
62 T: Hash + Eq + Clone,
63 S: BuildHasher + Clone,
64{
65 fn clone(&self) -> Self {
66 Self {
67 map: self.map.clone(),
68 }
69 }
70}
71
72impl<T, S> Default for OrderedHashSet<T, S>
73where
74 S: Default,
75{
76 fn default() -> Self {
77 Self {
78 map: Default::default(),
79 }
80 }
81}
82
83impl<T> OrderedHashSet<T, DefaultHashBuilder> {
84 /// Create an empty set.
85 ///
86 /// Capacity is 0 so the set will not allocated until inserted into.
87 /// ```
88 /// use ordered_hash_map::OrderedHashSet;
89 /// let set = OrderedHashSet::<i32>::new();
90 /// ```
91 pub fn new() -> Self {
92 Self::default()
93 }
94
95 /// Create an empty set with at least the specified capacity.
96 ///
97 /// The map will allocate if capacity is nonzero.
98 /// ```
99 /// use ordered_hash_map::OrderedHashSet;
100 /// let set = OrderedHashSet::<i32>::with_capacity(10);
101 /// assert!(set.capacity() >= 10)
102 /// ```
103 pub fn with_capacity(capacity: usize) -> Self {
104 Self {
105 map: ordered_map::OrderedHashMap::with_capacity(capacity),
106 }
107 }
108
109 /// Returns a draining iterator over the elements in insertion order.
110 ///
111 /// # Performance
112 /// This iterator visits each element once instead of each bucket once. This iterator is O(len)
113 /// which a usual map iterator is O(capacity) and may visit empty buckets.
114 /// ```
115 /// # use ordered_hash_map::OrderedHashSet;
116 /// let mut set: OrderedHashSet<i32> = [1i32, 2, 3, 4, 5].iter().collect();
117 /// assert_eq!(set.drain().next(), Some(1));
118 /// assert!(set.is_empty());
119 /// ```
120 pub fn drain(&mut self) -> Drain<'_, T> {
121 Drain {
122 inner: self.map.drain(),
123 }
124 }
125}
126
127impl<T, S> OrderedHashSet<T, S> {
128 /// Returns a draining iterator over the elements in insertion order.
129 ///
130 /// # Performance
131 /// This iterator visits each element once instead of each bucket once. This iterator is O(len)
132 /// which a usual map iterator is O(capacity) and may visit empty buckets.
133 /// ```
134 /// # use ordered_hash_map::OrderedHashSet;
135 /// use std::collections::hash_map::RandomState;
136 ///
137 /// let rs = RandomState::new();
138 /// let set = OrderedHashSet::<i32, _>::with_hasher(rs);
139 /// ```
140 pub const fn with_hasher(hash_builder: S) -> Self {
141 Self {
142 map: ordered_map::OrderedHashMap::with_hasher(hash_builder),
143 }
144 }
145
146 /// Create an empty set with the given capacity and which will use the given hasher.
147 ///
148 /// The map will allocate if capacity is nonzero.
149 /// ```no_run
150 /// # use ordered_hash_map::OrderedHashSet;
151 /// use std::collections::hash_map::RandomState;
152 ///
153 /// let rs = RandomState::new();
154 /// let set = OrderedHashSet::<i32, _>::with_capacity_and_hasher(10, rs);
155 /// assert!(set.capacity() >= 10)
156 /// ```
157 pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self {
158 Self {
159 map: ordered_map::OrderedHashMap::with_capacity_and_hasher(capacity, hash_builder),
160 }
161 }
162
163 /// Returns a reference to the sets hasher.
164 /// ```
165 /// # use ordered_hash_map::OrderedHashSet;
166 /// use std::collections::hash_map::RandomState;
167 ///
168 /// let rs = RandomState::new();
169 /// let set = OrderedHashSet::<i32, _>::with_hasher(rs);
170 /// let rs: &RandomState = set.hasher();
171 /// ```
172 pub fn hasher(&self) -> &S {
173 self.map.hasher()
174 }
175
176 /// The number of elements the set can hold without reallocating.
177 pub fn capacity(&self) -> usize {
178 self.map.capacity()
179 }
180
181 /// The number of elements currently held in the set.
182 pub fn len(&self) -> usize {
183 self.map.len()
184 }
185
186 /// Returns whether the set is empty.
187 pub fn is_empty(&self) -> bool {
188 self.map.is_empty()
189 }
190
191 /// Removes all values from the set.
192 pub fn clear(&mut self) {
193 self.map.clear();
194 }
195
196 /// Returns an iterator over the elements in insertion order.
197 ///
198 /// # Performance
199 /// This iterator visits each element once instead of each bucket once. This iterator is O(len)
200 /// which a usual map iterator is O(capacity) and may visit empty buckets.
201 pub fn iter(&self) -> Iter<'_, T> {
202 self.into_iter()
203 }
204}
205
206impl<T, S> OrderedHashSet<T, S>
207where
208 T: Eq + Hash,
209 S: BuildHasher,
210{
211 /// Insert a new element into the set. Returns whether the key already existed.
212 /// ```
213 /// # use ordered_hash_map::OrderedHashSet;
214 /// let mut set = OrderedHashSet::<i32>::new();
215 /// assert!(!set.insert(4));
216 /// assert!(set.insert(4));
217 /// ```
218 pub fn insert(&mut self, value: T) -> bool {
219 self.map.insert(value, ()).is_some()
220 }
221
222 /// Returns a reference to the value stored in the set.
223 /// ```
224 /// # use ordered_hash_map::OrderedHashSet;
225 /// let mut set = OrderedHashSet::<String>::new();
226 /// set.insert("A".to_string());
227 /// // Stored as String but can use &str to get
228 /// assert_eq!(set.get("A"), Some(&String::from("A")));
229 /// ```
230 pub fn get<Q>(&self, value: &Q) -> Option<&T>
231 where
232 T: Borrow<Q>,
233 Q: Hash + Eq + ?Sized,
234 {
235 self.map.get_key_value(value).map(|(x, _)| x)
236 }
237
238 /// Remove an element from the set, returning whether or not the element existed.
239 pub fn remove<Q>(&mut self, value: &Q) -> bool
240 where
241 T: Borrow<Q>,
242 Q: Hash + Eq + ?Sized,
243 {
244 self.map.remove(value).is_some()
245 }
246
247 /// Remove and return an element from the set
248 pub fn take<Q>(&mut self, value: &Q) -> Option<T>
249 where
250 T: Borrow<Q>,
251 Q: Hash + Eq + ?Sized,
252 {
253 self.map.remove_entry(value).map(|(x, _)| x)
254 }
255
256 /// Check if the set contains this key.
257 pub fn contains<Q>(&mut self, value: &Q) -> bool
258 where
259 T: Borrow<Q>,
260 Q: Hash + Eq + ?Sized,
261 {
262 self.map.contains_key(value)
263 }
264
265 /// Reserves capacity for at least `additional` more elements.
266 ///
267 /// # Panics
268 /// Panics if the new size would overflow a usize.
269 pub fn reserve(&mut self, additional: usize) {
270 self.map.reserve(additional);
271 }
272
273 /// Tries to reserve capacity for at least `additional` more elements.
274 ///
275 /// # Errors
276 /// Returns an error if the new size would overflow a usize.
277 pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
278 self.map.try_reserve(additional)
279 }
280
281 /// Shrinks the map as much as possible. May leave some space in accordance with the resize
282 /// policy.
283 pub fn shrink_to_fit(&mut self) {
284 self.map.shrink_to_fit();
285 }
286
287 /// Shrinks the map down to a lower limit. May leave some space in accordance with the resize
288 /// policy.
289 pub fn shrink_to(&mut self, min_capacity: usize) {
290 self.map.shrink_to(min_capacity);
291 }
292
293 /// Removes and returns the most recently inserted value, if there is one.
294 pub fn pop_back(&mut self) -> Option<T> {
295 self.map.pop_back_entry().map(|(x, _)| x)
296 }
297
298 /// Returns the most recently inserted value, if there is one
299 pub fn back(&self) -> Option<&T> {
300 self.map.back_entry().map(|(x, _)| x)
301 }
302
303 /// Remove and return the least recently inserted value, if there is one.
304 pub fn pop_front(&mut self) -> Option<T> {
305 self.map.pop_front_entry().map(|(x, _)| x)
306 }
307
308 /// Returns the most recently inserted value, if there is one
309 pub fn front(&self) -> Option<&T> {
310 self.map.front_entry().map(|(x, _)| x)
311 }
312
313 /// Move an element to the front of the list
314 pub fn move_to_front<Q>(&mut self, key: &Q)
315 where
316 T: Borrow<Q>,
317 Q: Hash + Eq + ?Sized,
318 {
319 self.map.move_to_front(key);
320 }
321
322 /// Move and element to the back of the list
323 pub fn move_to_back<Q>(&mut self, key: &Q)
324 where
325 T: Borrow<Q>,
326 Q: Hash + Eq + ?Sized,
327 {
328 self.map.move_to_back(key);
329 }
330}
331
332impl<T, S> PartialEq for OrderedHashSet<T, S>
333where
334 T: Eq + Hash,
335 S: BuildHasher,
336{
337 fn eq(&self, other: &OrderedHashSet<T, S>) -> bool {
338 self.map.eq(&other.map)
339 }
340}
341
342impl<T, S> Eq for OrderedHashSet<T, S>
343where
344 T: Eq + Hash,
345 S: BuildHasher,
346{
347}
348
349impl<T, Q, S> Index<&Q> for OrderedHashSet<T, S>
350where
351 T: Eq + Hash + Borrow<Q>,
352 Q: Eq + Hash + ?Sized,
353 S: BuildHasher,
354{
355 type Output = T;
356
357 fn index(&self, key: &Q) -> &T {
358 self.get(key).expect("no entry found for key")
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::OrderedHashSet;
365 #[test]
366 fn default() {
367 let set = OrderedHashSet::<i32>::new();
368 assert_eq!(set.len(), 0);
369 assert_eq!(set.iter().size_hint(), (0, Some(0)));
370 assert_eq!(set.iter().next(), None);
371 assert_eq!(set.iter().next_back(), None);
372 }
373
374 #[test]
375 fn clone() {
376 let set: OrderedHashSet<i32> = [1, 2, 3, 4].into_iter().collect();
377 let set_clone = set.clone();
378
379 assert_eq!(set, set_clone);
380 assert_eq!(format!("{:?}", set), format!("{:?}", set_clone));
381
382 set.iter()
383 .zip(set_clone.iter())
384 .for_each(|(val, val_clone)| assert_eq!(val, val_clone));
385
386 assert_eq!(set.len(), 4);
387
388 set.iter()
389 .rev()
390 .zip(set_clone.iter().rev())
391 .for_each(|(val, val_clone)| assert_eq!(val, val_clone));
392 }
393
394 #[test]
395 fn sizes() {
396 let mut set: OrderedHashSet<i32> = [1, 2, 3, 4].into_iter().collect();
397 assert_eq!(set.len(), 4);
398 assert!(!set.is_empty());
399
400 let mut drain = set.drain();
401 assert_eq!(drain.next(), Some(1));
402 assert_eq!(drain.next_back(), Some(4));
403
404 drop(drain); // Drop without consuming all of it
405
406 assert_eq!(set.len(), 0);
407 assert!(set.is_empty());
408
409 let mut set: OrderedHashSet<i32> = [1, 2, 3, 4].into_iter().collect();
410 set.clear();
411 assert_eq!(set.len(), 0);
412 assert!(set.is_empty());
413 }
414
415 #[test]
416 fn insert_remove_ops() {
417 let mut set = OrderedHashSet::<i32>::with_capacity(10);
418 assert!(set.capacity() >= 10);
419 set.reserve(15);
420 assert!(set.capacity() >= 25);
421
422 // First try on empty sets
423 assert!(!set.remove(&1));
424 assert!(set.get(&2).is_none());
425 assert!(set.take(&3).is_none());
426 assert!(set.back().is_none());
427 assert!(set.pop_back().is_none());
428 assert!(set.front().is_none());
429 assert!(set.pop_front().is_none());
430
431 set.move_to_front(&1); // Don't crash on non existent element
432
433 let mut set: OrderedHashSet<i32> = [1, 2, 3, 4].into_iter().collect();
434 assert!(!set.contains(&5));
435 assert!(!set.insert(5)); // [1, 2, 3, 4, 5]
436 assert!(set.insert(5)); // no change
437 assert!(set.contains(&5));
438 assert!(set.remove(&1)); // [2, 3, 4, 5]
439 assert_eq!(set[&2], 2); // no change
440 assert_eq!(set.take(&3), Some(3)); // [2, 4, 5]
441 assert_eq!(set.back(), Some(&5)); // no change
442 assert_eq!(set.pop_back(), Some(5)); // [2, 4]
443 assert_eq!(set.front(), Some(&2)); // no change
444 assert_eq!(set.pop_front(), Some(2)); // [4]
445 assert_eq!(set.get(&4), set.back());
446 assert_eq!(set.front(), set.back());
447 }
448
449 #[test]
450 fn move_to() {
451 let mut set: OrderedHashSet<i32> = [1, 2, 3].into_iter().collect();
452 set.move_to_front(&2);
453 assert_eq!(set, [2, 1, 3].into_iter().collect());
454 set.move_to_back(&2);
455 assert_eq!(set, [1, 3, 2].into_iter().collect());
456 }
457}