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