1use crate::analyzer::PatternMatcher;
2use memchr::memmem;
3use std::sync::OnceLock;
4
5struct CpuFeatures {
7 sse41_supported: bool,
8 avx2_supported: bool,
9}
10
11static CPU_FEATURES: OnceLock<CpuFeatures> = OnceLock::new();
12
13fn get_cpu_features() -> &'static CpuFeatures {
15 CPU_FEATURES.get_or_init(|| {
16 let mut features = CpuFeatures {
17 sse41_supported: false,
18 avx2_supported: false,
19 };
20
21 #[cfg(target_arch = "x86_64")]
22 {
23 if cfg!(feature = "simd_acceleration") {
24 features.sse41_supported = std::is_x86_feature_detected!("sse4.1");
25 features.avx2_supported = std::is_x86_feature_detected!("avx2");
26 }
27 }
28
29 features
30 })
31}
32
33pub struct SimdLiteralMatcher {
35 pattern_str: String,
37 pattern_bytes: Vec<u8>,
38}
39
40impl SimdLiteralMatcher {
41 pub fn new(pattern: &str) -> Self {
42 get_cpu_features();
44
45 Self {
46 pattern_str: pattern.to_string(),
47 pattern_bytes: pattern.as_bytes().to_vec(),
48 }
49 }
50
51 fn can_use_simd(&self) -> bool {
53 let min_pattern_length = 3;
55
56 #[cfg(not(feature = "simd_acceleration"))]
57 return false;
58
59 #[cfg(feature = "simd_acceleration")]
60 {
61 if self.pattern_bytes.len() < min_pattern_length {
63 return false;
64 }
65
66 let features = get_cpu_features();
68 features.sse41_supported || features.avx2_supported
69 }
70
71 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
72 false
73 }
74}
75
76impl PatternMatcher for SimdLiteralMatcher {
77 fn is_match(&self, text: &str) -> bool {
78 if self.can_use_simd() {
79 memmem::find(text.as_bytes(), &self.pattern_bytes).is_some()
81 } else {
82 text.contains(&self.pattern_str)
85 }
86 }
87}
88
89pub struct PatternMatcherFactory;
92
93impl PatternMatcherFactory {
94 pub fn create(pattern: &str) -> Box<dyn PatternMatcher + Send + Sync> {
101 if Self::is_complex_pattern(pattern) {
102 use crate::analyzer::RegexMatcher;
104 Box::new(RegexMatcher::new(pattern))
105 } else {
106 #[cfg(feature = "simd_acceleration")]
108 {
109 Box::new(SimdLiteralMatcher::new(pattern))
110 }
111
112 #[cfg(not(feature = "simd_acceleration"))]
114 {
115 use crate::analyzer::LiteralMatcher;
116 Box::new(LiteralMatcher::new(pattern))
117 }
118 }
119 }
120
121 fn is_complex_pattern(pattern: &str) -> bool {
123 pattern.contains(|c: char| {
125 c == '*'
126 || c == '?'
127 || c == '['
128 || c == '('
129 || c == '|'
130 || c == '+'
131 || c == '.'
132 || c == '^'
133 || c == '$'
134 || c == '\\'
135 })
136 }
137}
138
139pub mod line_processing {
141 use memchr::memchr_iter;
142
143 pub fn find_line_endings(buffer: &[u8]) -> Vec<usize> {
145 memchr_iter(b'\n', buffer).collect()
146 }
147
148 pub fn count_lines(buffer: &[u8]) -> usize {
150 memchr_iter(b'\n', buffer).count()
151 + if buffer.is_empty() || buffer[buffer.len() - 1] == b'\n' {
152 0
153 } else {
154 1
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn test_simd_literal_matcher_basic() {
165 let matcher = SimdLiteralMatcher::new("test");
166
167 assert!(matcher.is_match("This is a test string"));
168 assert!(!matcher.is_match("This does not match"));
169 }
170
171 #[test]
172 fn test_factory_creates_appropriate_matchers() {
173 let simple_matcher = PatternMatcherFactory::create("simple");
175 assert!(simple_matcher.is_match("simple pattern"));
176 assert!(!simple_matcher.is_match("not matching"));
177
178 let complex_matcher = PatternMatcherFactory::create("comp.ex|pattern");
180 assert!(complex_matcher.is_match("complex"));
181 assert!(complex_matcher.is_match("pattern"));
182 assert!(!complex_matcher.is_match("not matching"));
183 }
184
185 #[test]
186 fn test_line_processing() {
187 use super::line_processing::*;
188
189 let text = b"Line 1\nLine 2\nLine 3";
190 let line_endings = find_line_endings(text);
191
192 assert_eq!(line_endings, vec![6, 13]);
193 assert_eq!(count_lines(text), 3);
194 }
195}