zenoh_keyexpr/keyexpr_tree/iters/intersection.rs
1//
2// Copyright (c) 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12// ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14
15use alloc::vec::Vec;
16
17use zenoh_result::unlikely;
18
19use crate::keyexpr_tree::*;
20
21struct StackFrame<'a, Children: IChildrenProvider<Node>, Node: UIKeyExprTreeNode<Weight>, Weight>
22where
23 Children::Assoc: IChildren<Node> + 'a,
24 <Children::Assoc as IChildren<Node>>::Node: 'a,
25{
26 iterator: <Children::Assoc as IChildren<Node>>::Iter<'a>,
27 start: usize,
28 end: usize,
29 _marker: core::marker::PhantomData<Weight>,
30}
31pub struct Intersection<
32 'a,
33 Children: IChildrenProvider<Node>,
34 Node: UIKeyExprTreeNode<Weight>,
35 Weight,
36> where
37 Children::Assoc: IChildren<Node> + 'a,
38{
39 key: &'a keyexpr,
40 ke_indices: Vec<usize>,
41 iterators: Vec<StackFrame<'a, Children, Node, Weight>>,
42}
43
44impl<'a, Children: IChildrenProvider<Node>, Node: UIKeyExprTreeNode<Weight>, Weight>
45 Intersection<'a, Children, Node, Weight>
46where
47 Children::Assoc: IChildren<Node> + 'a,
48{
49 pub(crate) fn new(children: &'a Children::Assoc, key: &'a keyexpr) -> Self {
50 let mut ke_indices = Vec::with_capacity(32);
51 ke_indices.push(0);
52 let mut iterators = Vec::with_capacity(16);
53 iterators.push(StackFrame {
54 iterator: children.children(),
55 start: 0,
56 end: 1,
57 _marker: Default::default(),
58 });
59 Self {
60 key,
61 ke_indices,
62 iterators,
63 }
64 }
65}
66
67impl<
68 'a,
69 Children: IChildrenProvider<Node>,
70 Node: UIKeyExprTreeNode<Weight, Children = Children::Assoc> + 'a,
71 Weight,
72 > Iterator for Intersection<'a, Children, Node, Weight>
73where
74 Children::Assoc: IChildren<Node> + 'a,
75{
76 type Item = &'a Node;
77 fn next(&mut self) -> Option<Self::Item> {
78 loop {
79 let StackFrame {
80 iterator,
81 start,
82 end,
83 _marker,
84 } = self.iterators.last_mut()?;
85 match iterator.next() {
86 Some(node) => {
87 let mut node_matches = false;
88 let new_start = *end;
89 let mut new_end = *end;
90 macro_rules! push {
91 ($index: expr) => {
92 let index = $index;
93 if new_end == new_start || self.ke_indices[new_end - 1] < index {
94 self.ke_indices.push(index);
95 new_end += 1;
96 }
97 };
98 }
99 let chunk = node.chunk();
100 let chunk_is_verbatim = chunk.first_byte() == b'@';
101 if unlikely(chunk.as_bytes() == b"**") {
102 // If the current node is `**`, it is guaranteed to match...
103 node_matches = true;
104 // and may consume any number of chunks from the KE
105 push!(self.ke_indices[*start]);
106 if self.key.len() != self.ke_indices[*start] {
107 if self.key.as_bytes()[self.ke_indices[*start]] != b'@' {
108 for i in self.ke_indices[*start]..self.key.len() {
109 if self.key.as_bytes()[i] == b'/' {
110 push!(i + 1);
111 if self.key.as_bytes()[i + 1] == b'@' {
112 node_matches = false; // ...unless the KE contains a verbatim chunk.
113 break;
114 }
115 }
116 }
117 } else {
118 node_matches = false;
119 }
120 }
121 } else {
122 // The current node is not `**`
123 // For all candidate chunks of the KE
124 for i in *start..*end {
125 // construct that chunk, while checking whether or not it's the last one
126 let kec_start = self.ke_indices[i];
127 if unlikely(kec_start == self.key.len()) {
128 break;
129 }
130 let key = &self.key.as_bytes()[kec_start..];
131 match key.iter().position(|&c| c == b'/') {
132 Some(kec_end) => {
133 // If we aren't in the last chunk
134 let subkey =
135 // SAFETY: upheld by the surrounding invariants and prior validation.
136 unsafe { keyexpr::from_slice_unchecked(&key[..kec_end]) };
137 if unlikely(subkey.as_bytes() == b"**") {
138 if !chunk_is_verbatim {
139 // If the query chunk is `**`:
140 // children will have to process it again
141 push!(kec_start);
142 }
143 // and we need to process this chunk as if the `**` wasn't there,
144 // but with the knowledge that the next chunk won't be `**`.
145 let post_key = &key[kec_end + 1..];
146 match post_key.iter().position(|&c| c == b'/') {
147 Some(sec_end) => {
148 // SAFETY: upheld by the surrounding invariants and prior validation.
149 let post_key = unsafe {
150 keyexpr::from_slice_unchecked(
151 &post_key[..sec_end],
152 )
153 };
154 if post_key.intersects(chunk) {
155 push!(kec_start + kec_end + sec_end + 2);
156 }
157 }
158 None => {
159 // SAFETY: upheld by the surrounding invariants and prior validation.
160 if unsafe {
161 keyexpr::from_slice_unchecked(post_key)
162 }
163 .intersects(chunk)
164 {
165 push!(self.key.len());
166 node_matches = true;
167 }
168 }
169 }
170 } else if chunk.intersects(subkey) {
171 push!(kec_start + kec_end + 1);
172 }
173 }
174 None => {
175 // If it's the last chunk of the query, check whether it's `**`
176 // SAFETY: upheld by the surrounding invariants and prior validation.
177 let key = unsafe { keyexpr::from_slice_unchecked(key) };
178 if unlikely(key.as_bytes() == b"**") && !chunk_is_verbatim {
179 // If yes, it automatically matches, and must be reused from now on for iteration.
180 push!(kec_start);
181 node_matches = true;
182 } else if chunk.intersects(key) {
183 // else, if it intersects with the chunk, make sure the children of the node
184 // are searched for `**`
185 push!(self.key.len());
186 node_matches = true;
187 }
188 }
189 }
190 }
191 }
192 // If new progress points have been set
193 if new_end != new_start {
194 // Check if any of them is `**`, as this would mean a match
195 for &i in &self.ke_indices[new_start..new_end] {
196 if &self.key.as_bytes()[i..] == b"**" {
197 node_matches = true;
198 break;
199 }
200 }
201 // Prepare the next children
202 // SAFETY: upheld by the surrounding invariants and prior validation.
203 let iterator = unsafe { node.as_node().__children() }.children();
204 self.iterators.push(StackFrame {
205 iterator,
206 start: new_start,
207 end: new_end,
208 _marker: Default::default(),
209 })
210 }
211 // yield the node if a match was found
212 if node_matches {
213 return Some(node.as_node());
214 }
215 }
216 None => {
217 if let Some(StackFrame { start, .. }) = self.iterators.pop() {
218 self.ke_indices.truncate(start);
219 }
220 }
221 }
222 }
223 }
224}
225struct StackFrameMut<'a, Children: IChildrenProvider<Node>, Node: IKeyExprTreeNode<Weight>, Weight>
226where
227 Children::Assoc: IChildren<Node> + 'a,
228 <Children::Assoc as IChildren<Node>>::Node: 'a,
229{
230 iterator: <Children::Assoc as IChildren<Node>>::IterMut<'a>,
231 start: usize,
232 end: usize,
233 _marker: core::marker::PhantomData<Weight>,
234}
235
236pub struct IntersectionMut<
237 'a,
238 Children: IChildrenProvider<Node>,
239 Node: IKeyExprTreeNode<Weight>,
240 Weight,
241> where
242 Children::Assoc: IChildren<Node> + 'a,
243{
244 key: &'a keyexpr,
245 ke_indices: Vec<usize>,
246 iterators: Vec<StackFrameMut<'a, Children, Node, Weight>>,
247}
248
249impl<'a, Children: IChildrenProvider<Node>, Node: IKeyExprTreeNode<Weight>, Weight>
250 IntersectionMut<'a, Children, Node, Weight>
251where
252 Children::Assoc: IChildren<Node> + 'a,
253{
254 pub(crate) fn new(children: &'a mut Children::Assoc, key: &'a keyexpr) -> Self {
255 let mut ke_indices = Vec::with_capacity(32);
256 ke_indices.push(0);
257 let mut iterators = Vec::with_capacity(16);
258 iterators.push(StackFrameMut {
259 iterator: children.children_mut(),
260 start: 0,
261 end: 1,
262 _marker: Default::default(),
263 });
264 Self {
265 key,
266 ke_indices,
267 iterators,
268 }
269 }
270}
271
272impl<
273 'a,
274 Children: IChildrenProvider<Node>,
275 Node: IKeyExprTreeNodeMut<Weight, Children = Children::Assoc> + 'a,
276 Weight,
277 > Iterator for IntersectionMut<'a, Children, Node, Weight>
278where
279 Children::Assoc: IChildren<Node> + 'a,
280{
281 type Item = &'a mut <Children::Assoc as IChildren<Node>>::Node;
282 fn next(&mut self) -> Option<Self::Item> {
283 loop {
284 let StackFrameMut {
285 iterator,
286 start,
287 end,
288 _marker,
289 } = self.iterators.last_mut()?;
290 match iterator.next() {
291 Some(node) => {
292 let mut node_matches = false;
293 let new_start = *end;
294 let mut new_end = *end;
295 macro_rules! push {
296 ($index: expr) => {
297 let index = $index;
298 if new_end == new_start || self.ke_indices[new_end - 1] < index {
299 self.ke_indices.push(index);
300 new_end += 1;
301 }
302 };
303 }
304 let chunk = node.chunk();
305 let chunk_is_verbatim = chunk.first_byte() == b'@';
306 if unlikely(chunk.as_bytes() == b"**") {
307 // If the current node is `**`, it is guaranteed to match...
308 node_matches = true;
309 // and may consume any number of chunks from the KE
310 push!(self.ke_indices[*start]);
311 if self.key.len() != self.ke_indices[*start] {
312 if self.key.as_bytes()[self.ke_indices[*start]] != b'@' {
313 for i in self.ke_indices[*start]..self.key.len() {
314 if self.key.as_bytes()[i] == b'/' {
315 push!(i + 1);
316 if self.key.as_bytes()[i + 1] == b'@' {
317 node_matches = false; // ...unless the KE contains a verbatim chunk.
318 break;
319 }
320 }
321 }
322 } else {
323 node_matches = false;
324 }
325 }
326 } else {
327 // The current node is not `**`
328 // For all candidate chunks of the KE
329 for i in *start..*end {
330 // construct that chunk, while checking whether or not it's the last one
331 let kec_start = self.ke_indices[i];
332 if unlikely(kec_start == self.key.len()) {
333 break;
334 }
335 let key = &self.key.as_bytes()[kec_start..];
336 match key.iter().position(|&c| c == b'/') {
337 Some(kec_end) => {
338 // If we aren't in the last chunk
339 let subkey =
340 // SAFETY: upheld by the surrounding invariants and prior validation.
341 unsafe { keyexpr::from_slice_unchecked(&key[..kec_end]) };
342 if unlikely(subkey.as_bytes() == b"**") {
343 if !chunk_is_verbatim {
344 // If the query chunk is `**`:
345 // children will have to process it again
346 push!(kec_start);
347 }
348 // and we need to process this chunk as if the `**` wasn't there,
349 // but with the knowledge that the next chunk won't be `**`.
350 let post_key = &key[kec_end + 1..];
351 match post_key.iter().position(|&c| c == b'/') {
352 Some(sec_end) => {
353 // SAFETY: upheld by the surrounding invariants and prior validation.
354 let post_key = unsafe {
355 keyexpr::from_slice_unchecked(
356 &post_key[..sec_end],
357 )
358 };
359 if post_key.intersects(chunk) {
360 push!(kec_start + kec_end + sec_end + 2);
361 }
362 }
363 None => {
364 // SAFETY: upheld by the surrounding invariants and prior validation.
365 if unsafe {
366 keyexpr::from_slice_unchecked(post_key)
367 }
368 .intersects(chunk)
369 {
370 push!(self.key.len());
371 node_matches = true;
372 }
373 }
374 }
375 } else if chunk.intersects(subkey) {
376 push!(kec_start + kec_end + 1);
377 }
378 }
379 None => {
380 // If it's the last chunk of the query, check whether it's `**`
381 // SAFETY: upheld by the surrounding invariants and prior validation.
382 let key = unsafe { keyexpr::from_slice_unchecked(key) };
383 if unlikely(key.as_bytes() == b"**") && !chunk_is_verbatim {
384 // If yes, it automatically matches, and must be reused from now on for iteration.
385 push!(kec_start);
386 node_matches = true;
387 } else if chunk.intersects(key) {
388 // else, if it intersects with the chunk, make sure the children of the node
389 // are searched for `**`
390 push!(self.key.len());
391 node_matches = true;
392 }
393 }
394 }
395 }
396 }
397 if new_end != new_start {
398 for &i in &self.ke_indices[new_start..new_end] {
399 if &self.key.as_bytes()[i..] == b"**" {
400 node_matches = true;
401 break;
402 }
403 }
404 // SAFETY: upheld by the surrounding invariants and prior validation.
405 let iterator = unsafe { &mut *(node.as_node_mut() as *mut Node) }
406 .children_mut()
407 .children_mut();
408 self.iterators.push(StackFrameMut {
409 iterator,
410 start: new_start,
411 end: new_end,
412 _marker: Default::default(),
413 })
414 }
415 if node_matches {
416 return Some(node);
417 }
418 }
419 None => {
420 if let Some(StackFrameMut { start, .. }) = self.iterators.pop() {
421 self.ke_indices.truncate(start);
422 }
423 }
424 }
425 }
426 }
427}