1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/// Fast lookup table for compound operator second characters.
const COMPOUND_SECOND_CHARS: &[u8] = b"=<>&|+->.~*:";
#[inline]
pub(crate) fn is_compound_operator(first: char, second: char) -> bool {
// Optimized compound operator lookup using perfect hashing for common cases.
// Convert to bytes for faster comparison; most operators are ASCII.
if first.is_ascii() && second.is_ascii() {
let first_byte = first as u8;
let second_byte = second as u8;
if !COMPOUND_SECOND_CHARS.contains(&second_byte) {
return false;
}
// Use lookup table approach for maximum performance.
match (first_byte, second_byte) {
// Assignment operators.
(b'+' | b'-' | b'*' | b'/' | b'%' | b'&' | b'|' | b'^' | b'.', b'=') => true,
// Comparison operators.
(b'<' | b'>' | b'=' | b'!', b'=') => true,
// Pattern operators.
(b'=' | b'!', b'~') => true,
// Increment/decrement.
(b'+', b'+') | (b'-', b'-') => true,
// Logical operators.
(b'&', b'&') | (b'|', b'|') => true,
// Shift operators.
(b'<', b'<') | (b'>', b'>') => true,
// Other compound operators.
(b'*', b'*')
| (b'/', b'/')
| (b'-' | b'=', b'>')
| (b'.', b'.')
| (b'~', b'~')
| (b':', b':') => true,
_ => false,
}
} else {
// Fallback for non-ASCII, which should be rare.
matches!(
(first, second),
('+' | '-' | '*' | '/' | '%' | '&' | '|' | '^' | '.' | '<' | '>' | '=' | '!', '=')
| ('=' | '!' | '~', '~')
| ('+', '+')
| ('-', '-' | '>')
| ('&', '&')
| ('|', '|')
| ('<', '<')
| ('>' | '=', '>')
| ('*', '*')
| ('/', '/')
| ('.', '.')
| (':', ':')
)
}
}