(&self, si: StatePtr, text: &[u8], i: usize)
| 872 | /// This elides bounds checks, and is therefore unsafe. |
| 873 | #[inline(always)] |
| 874 | unsafe fn next_si(&self, si: StatePtr, text: &[u8], i: usize) -> StatePtr { |
| 875 | // What is the argument for safety here? |
| 876 | // We have three unchecked accesses that could possibly violate safety: |
| 877 | // |
| 878 | // 1. The given byte of input (`text[i]`). |
| 879 | // 2. The class of the byte of input (`classes[text[i]]`). |
| 880 | // 3. The transition for the class (`trans[si + cls]`). |
| 881 | // |
| 882 | // (1) is only safe when calling next_si is guarded by |
| 883 | // `i < text.len()`. |
| 884 | // |
| 885 | // (2) is the easiest case to guarantee since `text[i]` is always a |
| 886 | // `u8` and `self.prog.byte_classes` always has length `u8::MAX`. |
| 887 | // (See `ByteClassSet.byte_classes` in `compile.rs`.) |
| 888 | // |
| 889 | // (3) is only safe if (1)+(2) are safe. Namely, the transitions |
| 890 | // of every state are defined to have length equal to the number of |
| 891 | // byte classes in the program. Therefore, a valid class leads to a |
| 892 | // valid transition. (All possible transitions are valid lookups, even |
| 893 | // if it points to a state that hasn't been computed yet.) (3) also |
| 894 | // relies on `si` being correct, but StatePtrs should only ever be |
| 895 | // retrieved from the transition table, which ensures they are correct. |
| 896 | debug_assert!(i < text.len()); |
| 897 | let b = *text.get_unchecked(i); |
| 898 | debug_assert!((b as usize) < self.prog.byte_classes.len()); |
| 899 | let cls = *self.prog.byte_classes.get_unchecked(b as usize); |
| 900 | self.cache.trans.next_unchecked(si, cls as usize) |
| 901 | } |
| 902 | |
| 903 | /// Computes the next state given the current state and the current input |
| 904 | /// byte (which may be EOF). |
no test coverage detected