dfir_rs/compiled/pull/half_join_state/
set.rs1use std::borrow::Cow;
2use std::collections::VecDeque;
3use std::collections::hash_map::Entry;
4
5use super::HalfJoinState;
6
7type HashMap<K, V> = rustc_hash::FxHashMap<K, V>;
8
9use smallvec::{SmallVec, smallvec};
10
11#[derive(Debug)]
13pub struct HalfSetJoinState<Key, ValBuild, ValProbe> {
14 table: HashMap<Key, SmallVec<[ValBuild; 1]>>,
21 current_matches: VecDeque<(Key, ValProbe, ValBuild)>,
23 len: usize,
24}
25
26impl<Key, ValBuild, ValProbe> Default for HalfSetJoinState<Key, ValBuild, ValProbe> {
27 fn default() -> Self {
28 Self {
29 table: HashMap::default(),
30 current_matches: VecDeque::default(),
31 len: 0,
32 }
33 }
34}
35
36impl<Key, ValBuild, ValProbe> HalfJoinState<Key, ValBuild, ValProbe>
37 for HalfSetJoinState<Key, ValBuild, ValProbe>
38where
39 Key: Clone + Eq + std::hash::Hash,
40 ValBuild: Clone + Eq,
41 ValProbe: Clone,
42{
43 fn build(&mut self, k: Key, v: Cow<'_, ValBuild>) -> bool {
44 let entry = self.table.entry(k);
45
46 match entry {
47 Entry::Occupied(mut e) => {
48 let vec = e.get_mut();
49
50 if !vec.contains(v.as_ref()) {
51 vec.push(v.into_owned());
52 self.len += 1;
53 return true;
54 }
55 }
56 Entry::Vacant(e) => {
57 e.insert(smallvec![v.into_owned()]);
58 self.len += 1;
59 return true;
60 }
61 };
62
63 false
64 }
65
66 fn probe(&mut self, k: &Key, v: &ValProbe) -> Option<(Key, ValProbe, ValBuild)> {
67 let mut iter = self
71 .table
72 .get(k)?
73 .iter()
74 .map(|valbuild| (k.clone(), v.clone(), valbuild.clone()));
75
76 let first = iter.next();
77
78 self.current_matches.extend(iter);
79
80 first
81 }
82
83 fn full_probe(&self, k: &Key) -> std::slice::Iter<'_, ValBuild> {
84 let Some(sv) = self.table.get(k) else {
85 return [].iter();
86 };
87
88 sv.iter()
89 }
90
91 fn pop_match(&mut self) -> Option<(Key, ValProbe, ValBuild)> {
92 self.current_matches.pop_front()
93 }
94
95 fn len(&self) -> usize {
96 self.len
97 }
98
99 fn iter(&self) -> std::collections::hash_map::Iter<'_, Key, SmallVec<[ValBuild; 1]>> {
100 #[expect(clippy::disallowed_methods, reason = "FxHasher is deterministic")]
101 self.table.iter()
102 }
103
104 fn clear(&mut self) {
105 self.table.clear();
106 self.current_matches.clear();
107 self.len = 0;
108 }
109}