1use crate::dictionary::node_id::NodeId;
2use crate::error::Result;
3
4pub struct SimdScanner;
8
9impl SimdScanner {
10 pub fn scan_subject(triples: &[(NodeId, NodeId, NodeId)], target: NodeId) -> Vec<usize> {
12 let mut matches = Vec::new();
13
14 let subjects: Vec<u64> = triples.iter().map(|(s, _, _)| s.as_u64()).collect();
16
17 let target_val = target.as_u64();
19
20 for (i, &subj) in subjects.iter().enumerate() {
21 if subj == target_val {
22 matches.push(i);
23 }
24 }
25
26 matches
27 }
28
29 pub fn scan_predicate(triples: &[(NodeId, NodeId, NodeId)], target: NodeId) -> Vec<usize> {
31 let mut matches = Vec::new();
32
33 let predicates: Vec<u64> = triples.iter().map(|(_, p, _)| p.as_u64()).collect();
35
36 let target_val = target.as_u64();
37
38 for (i, &pred) in predicates.iter().enumerate() {
39 if pred == target_val {
40 matches.push(i);
41 }
42 }
43
44 matches
45 }
46
47 pub fn scan_object(triples: &[(NodeId, NodeId, NodeId)], target: NodeId) -> Vec<usize> {
49 let mut matches = Vec::new();
50
51 let objects: Vec<u64> = triples.iter().map(|(_, _, o)| o.as_u64()).collect();
53
54 let target_val = target.as_u64();
55
56 for (i, &obj) in objects.iter().enumerate() {
57 if obj == target_val {
58 matches.push(i);
59 }
60 }
61
62 matches
63 }
64
65 pub fn scan_subject_predicate(
67 triples: &[(NodeId, NodeId, NodeId)],
68 subject: NodeId,
69 predicate: NodeId,
70 ) -> Vec<usize> {
71 let mut matches = Vec::new();
72
73 let s_val = subject.as_u64();
74 let p_val = predicate.as_u64();
75
76 for (i, &(s, p, _)) in triples.iter().enumerate() {
77 if s.as_u64() == s_val && p.as_u64() == p_val {
78 matches.push(i);
79 }
80 }
81
82 matches
83 }
84
85 pub fn scan_predicate_object(
87 triples: &[(NodeId, NodeId, NodeId)],
88 predicate: NodeId,
89 object: NodeId,
90 ) -> Vec<usize> {
91 let mut matches = Vec::new();
92
93 let p_val = predicate.as_u64();
94 let o_val = object.as_u64();
95
96 for (i, &(_, p, o)) in triples.iter().enumerate() {
97 if p.as_u64() == p_val && o.as_u64() == o_val {
98 matches.push(i);
99 }
100 }
101
102 matches
103 }
104
105 pub fn scan_subject_object(
107 triples: &[(NodeId, NodeId, NodeId)],
108 subject: NodeId,
109 object: NodeId,
110 ) -> Vec<usize> {
111 let mut matches = Vec::new();
112
113 let s_val = subject.as_u64();
114 let o_val = object.as_u64();
115
116 for (i, &(s, _, o)) in triples.iter().enumerate() {
117 if s.as_u64() == s_val && o.as_u64() == o_val {
118 matches.push(i);
119 }
120 }
121
122 matches
123 }
124
125 pub fn parallel_scan_subject(
127 triples: &[(NodeId, NodeId, NodeId)],
128 target: NodeId,
129 chunk_size: usize,
130 ) -> Vec<usize> {
131 let mut all_matches = Vec::new();
132 let target_val = target.as_u64();
133
134 let chunks: Vec<_> = triples.chunks(chunk_size).collect();
136
137 for (chunk_idx, chunk) in chunks.iter().enumerate() {
138 for (i, &(s, _, _)) in chunk.iter().enumerate() {
139 if s.as_u64() == target_val {
140 all_matches.push(chunk_idx * chunk_size + i);
141 }
142 }
143 }
144
145 all_matches
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 fn create_test_triples() -> Vec<(NodeId, NodeId, NodeId)> {
154 vec![
155 (NodeId::new(1), NodeId::new(10), NodeId::new(100)),
156 (NodeId::new(1), NodeId::new(11), NodeId::new(101)),
157 (NodeId::new(2), NodeId::new(10), NodeId::new(102)),
158 (NodeId::new(2), NodeId::new(12), NodeId::new(100)),
159 (NodeId::new(3), NodeId::new(10), NodeId::new(103)),
160 ]
161 }
162
163 #[test]
164 fn test_scan_subject() {
165 let triples = create_test_triples();
166 let matches = SimdScanner::scan_subject(&triples, NodeId::new(1));
167
168 assert_eq!(matches, vec![0, 1]);
169 }
170
171 #[test]
172 fn test_scan_predicate() {
173 let triples = create_test_triples();
174 let matches = SimdScanner::scan_predicate(&triples, NodeId::new(10));
175
176 assert_eq!(matches, vec![0, 2, 4]);
177 }
178
179 #[test]
180 fn test_scan_object() {
181 let triples = create_test_triples();
182 let matches = SimdScanner::scan_object(&triples, NodeId::new(100));
183
184 assert_eq!(matches, vec![0, 3]);
185 }
186
187 #[test]
188 fn test_scan_subject_predicate() {
189 let triples = create_test_triples();
190 let matches =
191 SimdScanner::scan_subject_predicate(&triples, NodeId::new(1), NodeId::new(10));
192
193 assert_eq!(matches, vec![0]);
194 }
195
196 #[test]
197 fn test_scan_predicate_object() {
198 let triples = create_test_triples();
199 let matches =
200 SimdScanner::scan_predicate_object(&triples, NodeId::new(10), NodeId::new(100));
201
202 assert_eq!(matches, vec![0]);
203 }
204
205 #[test]
206 fn test_scan_subject_object() {
207 let triples = create_test_triples();
208 let matches = SimdScanner::scan_subject_object(&triples, NodeId::new(2), NodeId::new(100));
209
210 assert_eq!(matches, vec![3]);
211 }
212
213 #[test]
214 fn test_scan_no_matches() {
215 let triples = create_test_triples();
216 let matches = SimdScanner::scan_subject(&triples, NodeId::new(999));
217
218 assert_eq!(matches, Vec::<usize>::new());
219 }
220
221 #[test]
222 fn test_parallel_scan_subject() {
223 let triples = create_test_triples();
224 let matches = SimdScanner::parallel_scan_subject(&triples, NodeId::new(1), 2);
225
226 assert_eq!(matches, vec![0, 1]);
227 }
228
229 #[test]
230 fn test_scan_empty_array() {
231 let triples: Vec<(NodeId, NodeId, NodeId)> = vec![];
232 let matches = SimdScanner::scan_subject(&triples, NodeId::new(1));
233
234 assert_eq!(matches, Vec::<usize>::new());
235 }
236
237 #[test]
238 fn test_scan_large_array() {
239 let mut triples = Vec::new();
240 for i in 0..1000 {
241 triples.push((NodeId::new(i % 10), NodeId::new(i % 5), NodeId::new(i)));
242 }
243
244 let matches = SimdScanner::scan_subject(&triples, NodeId::new(5));
245 assert_eq!(matches.len(), 100); }
247}