Skip to main content

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}