1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
45use std::collections::{HashMap, HashSet};
6use std::sync::atomic::{AtomicU32, Ordering};
78/// Finds the maximum of the current value and the argument `val`, and sets the
9/// new value to the result.
10///
11/// Note: `AtomicFoo::fetch_max` is unstable, and can't really be implemented as
12/// a single atomic operation from outside the stdlib ;-;
13pub(crate) fn atomic_update_max(v: &AtomicU32, new: u32) {
14// For loads (and the compare_exchange_weak second ordering argument) this
15 // is too strong, we could probably get away with Acquire (or maybe Relaxed
16 // because we don't need the result?). In either case, this fn isn't called
17 // from a hot spot so whatever.
18let mut cur = v.load(Ordering::SeqCst);
19while cur < new {
20// we're already handling the failure case so there's no reason not to
21 // use _weak here.
22match v.compare_exchange_weak(cur, new, Ordering::SeqCst, Ordering::SeqCst) {
23Ok(_) => {
24// Success.
25break;
26 }
27Err(new_cur) => {
28// Interrupted, keep trying.
29cur = new_cur
30 }
31 }
32 }
33}
3435// Slight wrappers around the builtin methods for doing this.
36pub(crate) fn set_union(a: &HashSet<String>, b: &HashSet<String>) -> HashSet<String> {
37 a.union(b).cloned().collect()
38}
3940pub(crate) fn set_difference(a: &HashSet<String>, b: &HashSet<String>) -> HashSet<String> {
41 a.difference(b).cloned().collect()
42}
4344pub(crate) fn set_intersection(a: &HashSet<String>, b: &HashSet<String>) -> HashSet<String> {
45 a.intersection(b).cloned().collect()
46}
4748pub(crate) fn partition_by_value(v: &HashMap<String, bool>) -> (HashSet<String>, HashSet<String>) {
49let mut true_: HashSet<String> = HashSet::new();
50let mut false_: HashSet<String> = HashSet::new();
51for (s, val) in v {
52if *val {
53 true_.insert(s.clone());
54 } else {
55 false_.insert(s.clone());
56 }
57 }
58 (true_, false_)
59}
6061#[cfg(test)]
62mod test {
63use super::*;
6465#[test]
66fn test_set_ops() {
67fn hash_set(s: &[&str]) -> HashSet<String> {
68 s.iter()
69 .copied()
70 .map(ToOwned::to_owned)
71 .collect::<HashSet<_>>()
72 }
7374assert_eq!(
75 set_union(&hash_set(&["a", "b", "c"]), &hash_set(&["b", "d"])),
76 hash_set(&["a", "b", "c", "d"]),
77 );
7879assert_eq!(
80 set_difference(&hash_set(&["a", "b", "c"]), &hash_set(&["b", "d"])),
81 hash_set(&["a", "c"]),
82 );
83assert_eq!(
84 set_intersection(&hash_set(&["a", "b", "c"]), &hash_set(&["b", "d"])),
85 hash_set(&["b"]),
86 );
87let m: HashMap<String, bool> = [
88 ("foo", true),
89 ("bar", true),
90 ("baz", false),
91 ("quux", false),
92 ]
93 .iter()
94 .copied()
95 .map(|(a, b)| (a.to_owned(), b))
96 .collect();
97assert_eq!(
98 partition_by_value(&m),
99 (hash_set(&["foo", "bar"]), hash_set(&["baz", "quux"])),
100 );
101 }
102}