1mod edit;
18#[cfg(test)]
19mod test_basic;
20#[cfg(test)]
21mod test_ported;
22
23pub use self::edit::InputEditor;
24use crate::dic::category_type::CategoryType;
25use crate::dic::grammar::Grammar;
26use std::ops::Range;
27
28use crate::error::{SudachiError, SudachiResult};
29use crate::input_text::InputTextIndex;
30
31const MAX_LENGTH: usize = u16::MAX as usize / 4 * 3;
33
34const REALLY_MAX_LENGTH: usize = u16::MAX as usize;
36
37#[derive(Eq, PartialEq, Debug, Clone, Default)]
38enum BufferState {
39 #[default]
40 Clean,
41 RW,
42 RO,
43}
44
45#[derive(Default, Clone)]
50pub struct InputBuffer {
51 original: String,
53 modified: String,
55 modified_2: String,
57 m2o: Vec<usize>,
60 m2o_2: Vec<usize>,
63 mod_chars: Vec<char>,
65 mod_c2b: Vec<usize>,
67 mod_b2c: Vec<usize>,
69 mod_bow: Vec<bool>,
71 mod_cat: Vec<CategoryType>,
73 mod_cat_continuity: Vec<usize>,
75 replaces: Vec<edit::ReplaceOp<'static>>,
79 state: BufferState,
81}
82
83impl InputBuffer {
84 pub fn new() -> InputBuffer {
86 InputBuffer::default()
87 }
88
89 pub fn reset(&mut self) -> &mut String {
92 self.original.clear();
95 self.modified.clear();
96 self.m2o.clear();
97 self.mod_chars.clear();
98 self.mod_c2b.clear();
99 self.mod_b2c.clear();
100 self.mod_bow.clear();
101 self.mod_cat.clear();
102 self.mod_cat_continuity.clear();
103 self.state = BufferState::Clean;
104 &mut self.original
105 }
106
107 pub fn from<T: AsRef<str>>(data: T) -> InputBuffer {
111 let mut buf = Self::new();
112 buf.reset().push_str(data.as_ref());
113 buf.start_build().expect("");
114 buf
115 }
116
117 pub fn start_build(&mut self) -> SudachiResult<()> {
119 if self.original.len() > MAX_LENGTH {
120 return Err(SudachiError::InputTooLong(self.original.len(), MAX_LENGTH));
121 }
122 debug_assert_eq!(self.state, BufferState::Clean);
123 self.state = BufferState::RW;
124 self.modified.push_str(&self.original);
125 self.m2o.extend(0..self.modified.len() + 1);
126 Ok(())
127 }
128
129 pub fn build(&mut self, grammar: &Grammar) -> SudachiResult<()> {
131 debug_assert_eq!(self.state, BufferState::RW);
132 self.state = BufferState::RO;
133 self.mod_chars.clear();
134 let cats = &grammar.character_category;
135 let mut last_offset = 0;
136 let mut last_chidx = 0;
137
138 let non_starting = CategoryType::ALPHA | CategoryType::GREEK | CategoryType::CYRILLIC;
141 let mut prev_cat = CategoryType::empty();
142 self.mod_bow.resize(self.modified.len(), false);
143
144 for (chidx, (bidx, ch)) in self.modified.char_indices().enumerate() {
145 self.mod_chars.push(ch);
146 let cat = cats.get_category_types(ch);
147 self.mod_cat.push(cat);
148 self.mod_c2b.push(bidx);
149 self.mod_b2c
150 .extend(std::iter::repeat(last_chidx).take(bidx - last_offset));
151 last_offset = bidx;
152 last_chidx = chidx;
153
154 let can_bow = if cat.intersects(non_starting) {
155 !cat.intersects(prev_cat)
157 } else {
158 true
159 };
160
161 self.mod_bow[bidx] = can_bow;
162 prev_cat = cat;
163 }
164 self.mod_b2c
166 .extend(std::iter::repeat(last_chidx).take(self.modified.len() - last_offset));
167 self.mod_c2b.push(self.mod_b2c.len());
169 self.mod_b2c.push(last_chidx + 1);
170
171 self.fill_cat_continuity();
172 self.fill_orig_b2c();
173
174 Ok(())
175 }
176
177 fn fill_cat_continuity(&mut self) {
178 if self.mod_chars.is_empty() {
179 return;
180 }
181 self.mod_cat_continuity.clear();
182 self.mod_cat_continuity.reserve(self.mod_cat.len());
183
184 let mut length = 1;
185 for start in 0..self.mod_cat.len() {
186 if length > 1 {
188 length -= 1;
189 self.mod_cat_continuity.push(length);
190 continue;
191 }
192
193 let mut common = self.mod_cat[start];
194 length = 1;
195 while start + length < self.mod_cat.len() {
196 common &= self.mod_cat[start + length];
197 if common.is_empty() {
198 break;
199 }
200 length += 1;
201 }
202 self.mod_cat_continuity.push(length);
203 }
204 }
205
206 fn fill_orig_b2c(&mut self) {
207 self.m2o_2.clear();
208 self.m2o_2.resize(self.original.len() + 1, usize::MAX);
209 let mut max = 0;
210 for (ch_idx, (b_idx, _)) in self.original.char_indices().enumerate() {
211 self.m2o_2[b_idx] = ch_idx;
212 max = ch_idx
213 }
214 self.m2o_2[self.original.len()] = max + 1;
215 }
216
217 fn commit(&mut self) -> SudachiResult<()> {
218 if self.replaces.is_empty() {
219 return Ok(());
220 }
221
222 self.mod_chars.clear();
223 self.modified_2.clear();
224 self.m2o_2.clear();
225
226 let sz = edit::resolve_edits(
227 &self.modified,
228 &self.m2o,
229 &mut self.modified_2,
230 &mut self.m2o_2,
231 &mut self.replaces,
232 );
233 if sz > REALLY_MAX_LENGTH {
234 return Err(SudachiError::InputTooLong(sz, REALLY_MAX_LENGTH));
236 }
237 std::mem::swap(&mut self.modified, &mut self.modified_2);
238 std::mem::swap(&mut self.m2o, &mut self.m2o_2);
239 Ok(())
240 }
241
242 fn rollback(&mut self) {
243 self.replaces.clear()
244 }
245
246 fn make_editor<'a>(&mut self) -> InputEditor<'a> {
247 let replaces: &'a mut Vec<edit::ReplaceOp<'a>> =
250 unsafe { std::mem::transmute(&mut self.replaces) };
251 InputEditor::new(replaces)
252 }
253
254 pub fn with_editor<'a, F>(&mut self, func: F) -> SudachiResult<()>
258 where
259 F: FnOnce(&InputBuffer, InputEditor<'a>) -> SudachiResult<InputEditor<'a>>,
260 F: 'a,
261 {
262 debug_assert_eq!(self.state, BufferState::RW);
263 let editor: InputEditor<'a> = self.make_editor();
267 match func(self, editor) {
268 Ok(_) => self.commit(),
269 Err(e) => {
270 self.rollback();
271 Err(e)
272 }
273 }
274 }
275
276 pub fn refresh_chars(&mut self) {
278 debug_assert_eq!(self.state, BufferState::RW);
279 if self.mod_chars.is_empty() {
280 self.mod_chars.extend(self.modified.chars());
281 }
282 }
283}
284
285impl InputBuffer {
287 pub fn original(&self) -> &str {
289 debug_assert_ne!(self.state, BufferState::Clean);
290 &self.original
291 }
292
293 pub fn current(&self) -> &str {
295 debug_assert_ne!(self.state, BufferState::Clean);
296 &self.modified
297 }
298
299 pub fn current_chars(&self) -> &[char] {
301 debug_assert_ne!(self.state, BufferState::Clean);
302 debug_assert_eq!(self.modified.is_empty(), self.mod_chars.is_empty());
303 &self.mod_chars
304 }
305
306 pub fn curr_byte_offsets(&self) -> &[usize] {
308 debug_assert_eq!(self.state, BufferState::RO);
309 let len = self.mod_c2b.len();
310 &self.mod_c2b[0..len - 1]
311 }
312
313 pub fn get_original_index(&self, index: usize) -> usize {
316 debug_assert!(self.modified.is_char_boundary(index));
317 self.m2o[index]
318 }
319
320 pub fn to_orig_byte_idx(&self, index: usize) -> usize {
322 debug_assert_ne!(self.state, BufferState::Clean);
323 let byte_idx = self.mod_c2b[index];
324 self.m2o[byte_idx]
325 }
326
327 pub fn to_orig_char_idx(&self, index: usize) -> usize {
329 let b_idx = self.to_orig_byte_idx(index);
330 let res = self.m2o_2[b_idx];
331 debug_assert_ne!(res, usize::MAX);
332 res
333 }
334
335 pub fn to_curr_byte_idx(&self, index: usize) -> usize {
337 debug_assert_eq!(self.state, BufferState::RO);
338 self.mod_c2b[index]
339 }
340
341 pub fn curr_slice_c(&self, data: Range<usize>) -> &str {
343 debug_assert_eq!(self.state, BufferState::RO);
344 let start = self.mod_c2b[data.start];
345 let end = self.mod_c2b[data.end];
346 &self.modified[start..end]
347 }
348
349 pub fn orig_slice_c(&self, data: Range<usize>) -> &str {
351 debug_assert_eq!(self.state, BufferState::RO);
352 let start = self.to_orig_byte_idx(data.start);
353 let end = self.to_orig_byte_idx(data.end);
354 &self.original[start..end]
355 }
356
357 pub fn ch_idx(&self, idx: usize) -> usize {
358 debug_assert_eq!(self.state, BufferState::RO);
359 self.mod_b2c[idx]
360 }
361
362 pub fn swap_original(&mut self, target: &mut String) {
364 std::mem::swap(&mut self.original, target);
365 self.state = BufferState::Clean;
366 }
367
368 pub fn into_original(self) -> String {
370 self.original
371 }
372
373 #[inline]
376 pub fn can_bow(&self, offset: usize) -> bool {
377 debug_assert_eq!(self.state, BufferState::RO);
378 self.mod_bow[offset]
379 }
380
381 #[inline]
383 pub fn can_oov_bow(&self, offset: usize) -> bool {
384 debug_assert_eq!(self.state, BufferState::RO);
385 let cat = self.mod_cat[offset];
386 !cat.contains(CategoryType::NOOOVBOW)
387 && (offset == 0 || !self.mod_cat[offset - 1].contains(CategoryType::NOOOVEOW))
388 }
389
390 pub fn get_word_candidate_length(&self, char_idx: usize) -> usize {
394 debug_assert_eq!(self.state, BufferState::RO);
395 let char_len = self.mod_chars.len();
396
397 for i in (char_idx + 1)..char_len {
398 let byte_idx = self.mod_c2b[i];
399 if self.can_bow(byte_idx) {
400 return i - char_idx;
401 }
402 }
403 char_len - char_idx
404 }
405}
406
407impl InputTextIndex for InputBuffer {
408 #[inline]
409 fn cat_of_range(&self, range: Range<usize>) -> CategoryType {
410 debug_assert_eq!(self.state, BufferState::RO);
411 if range.is_empty() {
412 return CategoryType::empty();
413 }
414
415 self.mod_cat[range]
416 .iter()
417 .fold(CategoryType::all(), |a, b| a & *b)
418 }
419
420 #[inline]
421 fn cat_at_char(&self, offset: usize) -> CategoryType {
422 debug_assert_eq!(self.state, BufferState::RO);
423 self.mod_cat[offset]
424 }
425
426 #[inline]
427 fn cat_continuous_len(&self, offset: usize) -> usize {
428 debug_assert_eq!(self.state, BufferState::RO);
429 self.mod_cat_continuity[offset]
430 }
431
432 fn char_distance(&self, cpt: usize, offset: usize) -> usize {
433 debug_assert_eq!(self.state, BufferState::RO);
434 let end = (cpt + offset).min(self.mod_chars.len());
435 end - cpt
436 }
437
438 #[inline]
439 fn orig_slice(&self, range: Range<usize>) -> &str {
440 debug_assert_ne!(self.state, BufferState::Clean);
441 debug_assert!(
442 self.modified.is_char_boundary(range.start),
443 "start is off char boundary"
444 );
445 debug_assert!(
446 self.modified.is_char_boundary(range.end),
447 "end is off char boundary"
448 );
449 &self.original[self.to_orig(range)]
450 }
451
452 #[inline]
453 fn curr_slice(&self, range: Range<usize>) -> &str {
454 debug_assert_ne!(self.state, BufferState::Clean);
455 &self.modified[range]
456 }
457
458 #[inline]
459 fn to_orig(&self, range: Range<usize>) -> Range<usize> {
460 debug_assert_ne!(self.state, BufferState::Clean);
461 self.m2o[range.start]..self.m2o[range.end]
462 }
463}