1use crate::change::get_sys_timestamp;
18use fxhash::FxHashMap;
19use std::cmp::Ordering;
20use std::collections::BinaryHeap;
21use std::iter::zip;
22use std::ops::{Index, IndexMut};
23
24#[derive(Clone, Debug)]
29pub struct UpdateOptions {
30 pub timeout_ms: Option<f64>,
31 pub use_refined_diff: bool,
32}
33
34impl Default for UpdateOptions {
35 fn default() -> Self {
36 Self {
37 timeout_ms: None,
38 use_refined_diff: true,
39 }
40 }
41}
42
43#[derive(thiserror::Error, Debug, PartialEq)]
44pub enum UpdateTimeoutError {
45 #[error("Timeout")]
46 Timeout,
47}
48
49#[inline(always)]
51fn is_empty_range(start: usize, end: usize) -> bool {
52 start >= end
53}
54
55#[inline(always)]
56fn is_not_empty_range(start: usize, end: usize) -> bool {
57 start < end
58}
59
60fn common_prefix(xs: &[u32], ys: &[u32]) -> usize {
61 let chunk_size = 4;
62 let off = zip(xs.chunks_exact(chunk_size), ys.chunks_exact(chunk_size))
63 .take_while(|(xs_chunk, ys_chunk)| xs_chunk == ys_chunk)
64 .count()
65 * chunk_size;
66 off + zip(&xs[off..], &ys[off..])
67 .take_while(|(x, y)| x == y)
68 .count()
69}
70
71fn common_suffix_len(old: &[u32], new: &[u32]) -> usize {
72 let chunk_size = 4;
73 let old_len = old.len();
74 let new_len = new.len();
75
76 let off = zip(old.rchunks_exact(chunk_size), new.rchunks_exact(chunk_size))
77 .take_while(|(old_chunk, new_chunk)| old_chunk == new_chunk)
78 .count()
79 * chunk_size;
80
81 off + zip(
82 old[..old_len - off].iter().rev(),
83 new[..new_len - off].iter().rev(),
84 )
85 .take_while(|(o, n)| o == n)
86 .count()
87}
88
89pub(crate) trait DiffHandler {
90 fn insert(&mut self, old_index: usize, new_index: usize, new_len: usize);
91 fn delete(&mut self, old_index: usize, old_len: usize);
92}
93
94#[derive(Debug)]
95pub(crate) struct OperateProxy<D: DiffHandler> {
96 handler: D,
97}
98
99impl<D: DiffHandler> OperateProxy<D> {
100 pub fn new(handler: D) -> Self {
101 Self { handler }
102 }
103
104 pub fn delete(&mut self, old_index: usize, old_len: usize) {
105 self.handler.delete(old_index, old_len);
106 }
107
108 pub fn insert(&mut self, old_index: usize, new_index: usize, new_len: usize) {
109 self.handler.insert(old_index, new_index, new_len);
110 }
111
112 #[allow(unused)]
113 fn unwrap(self) -> D {
114 self.handler
115 }
116}
117
118pub(crate) fn diff<D: DiffHandler>(
119 proxy: &mut OperateProxy<D>,
120 options: UpdateOptions,
121 old: &[u32],
122 new: &[u32],
123) -> Result<(), UpdateTimeoutError> {
124 let max_d = (old.len() + new.len()).div_ceil(2) + 1;
125 let mut vb = OffsetVec::new(max_d);
126 let mut vf = OffsetVec::new(max_d);
127 let start_time = if options.timeout_ms.is_some() {
128 get_sys_timestamp()
129 } else {
130 0.
131 };
132
133 conquer(
134 proxy,
135 options.use_refined_diff,
136 options.timeout_ms,
137 start_time,
138 old,
139 0,
140 old.len(),
141 new,
142 0,
143 new.len(),
144 &mut vf,
145 &mut vb,
146 )
147}
148
149struct OffsetVec(isize, Vec<usize>);
150
151impl OffsetVec {
152 fn new(max_d: usize) -> Self {
153 Self(max_d as isize, vec![0; max_d << 1])
154 }
155
156 fn len(&self) -> usize {
157 self.1.len()
158 }
159}
160
161impl Index<isize> for OffsetVec {
162 type Output = usize;
163 fn index(&self, index: isize) -> &Self::Output {
164 &self.1[(index + self.0) as usize]
165 }
166}
167
168impl IndexMut<isize> for OffsetVec {
169 fn index_mut(&mut self, index: isize) -> &mut Self::Output {
170 &mut self.1[(index + self.0) as usize]
171 }
172}
173
174struct MiddleSnakeResult {
175 #[allow(unused)]
176 d: usize,
177 x_start: usize,
178 y_start: usize,
179}
180
181#[allow(clippy::too_many_arguments)]
182fn find_middle_snake(
183 timeout_ms: Option<f64>,
184 start_time: f64,
185 old: &[u32],
186 old_start: usize,
187 old_end: usize,
188 new: &[u32],
189 new_start: usize,
190 new_end: usize,
191 vf: &mut OffsetVec,
192 vb: &mut OffsetVec,
193) -> Result<Option<MiddleSnakeResult>, UpdateTimeoutError> {
194 let n = old_end - old_start;
195 let m = new_end - new_start;
196 let delta = n as isize - m as isize;
197 let odd = delta & 1 != 0;
198 vf[1] = 0;
199 vb[1] = 0;
200 let d_max = (n + m).div_ceil(2) + 1;
201 assert!(vf.len() >= d_max);
202 assert!(vb.len() >= d_max);
203
204 for d in 0..d_max as isize {
205 for k in (-d..=d).rev().step_by(2) {
206 let mut x = if k == -d || (k != d && vf[k - 1] < vf[k + 1]) {
207 vf[k + 1]
208 } else {
209 vf[k - 1] + 1
210 };
211 let y = (x as isize - k) as usize;
212 let (x0, y0) = (x, y);
213 if x < n && y < m {
214 let advance =
215 common_prefix(&old[old_start + x..old_end], &new[new_start + y..new_end]);
216 x += advance;
217 }
218 vf[k] = x;
219 if odd && (k - delta).abs() <= (d - 1) && vf[k] + vb[delta - k] >= n {
220 return Ok(Some(MiddleSnakeResult {
221 d: d as usize,
222 x_start: x0 + old_start,
223 y_start: y0 + new_start,
224 }));
225 }
226
227 if let Some(timeout_ms) = timeout_ms {
228 if get_sys_timestamp() - start_time > timeout_ms {
229 return Err(UpdateTimeoutError::Timeout);
230 }
231 }
232 }
233
234 for k in (-d..=d).rev().step_by(2) {
235 let mut x = if k == -d || (k != d && vb[k - 1] < vb[k + 1]) {
236 vb[k + 1]
237 } else {
238 vb[k - 1] + 1
239 };
240 let mut y = (x as isize - k) as usize;
241 if x < n && y < m {
242 let advance = common_suffix_len(
243 &old[old_start..old_start + n - x],
244 &new[new_start..new_start + m - y],
245 );
246 x += advance;
247 y += advance;
248 }
249 vb[k] = x;
250 if !odd && (k - delta).abs() <= d && vb[k] + vf[delta - k] >= n {
251 return Ok(Some(MiddleSnakeResult {
252 d: d as usize,
253 x_start: n - x + old_start,
254 y_start: m - y + new_start,
255 }));
256 }
257
258 if let Some(timeout_ms) = timeout_ms {
259 if get_sys_timestamp() - start_time > timeout_ms {
260 return Err(UpdateTimeoutError::Timeout);
261 }
262 }
263 }
264 }
265
266 Ok(None)
267}
268
269#[allow(clippy::too_many_arguments)]
270fn conquer<D: DiffHandler>(
271 proxy: &mut OperateProxy<D>,
272 should_use_dj: bool,
273 timeout_ms: Option<f64>,
274 start_time: f64,
275 old: &[u32],
276 mut old_start: usize,
277 mut old_end: usize,
278 new: &[u32],
279 mut new_start: usize,
280 mut new_end: usize,
281 vf: &mut OffsetVec,
282 vb: &mut OffsetVec,
283) -> Result<(), UpdateTimeoutError> {
284 let common_prefix_len = common_prefix(&old[old_start..old_end], &new[new_start..new_end]);
285 if common_prefix_len > 0 {
286 old_start += common_prefix_len;
287 new_start += common_prefix_len;
288 }
289
290 let common_suffix_len = common_suffix_len(&old[old_start..old_end], &new[new_start..new_end]);
291 old_end -= common_suffix_len;
292 new_end -= common_suffix_len;
293
294 if is_not_empty_range(old_start, old_end) || is_not_empty_range(new_start, new_end) {
295 let len_old = old_end - old_start;
296 let len_new = new_end - new_start;
297 if should_use_dj && (len_old.max(1) * len_new.max(1) < 128 * 128) {
298 let ok = dj_diff(
299 proxy,
300 &old[old_start..old_end],
301 &new[new_start..new_end],
302 old_start,
303 new_start,
304 10_000,
305 );
306 if ok {
307 return Ok(());
308 }
309 }
310
311 if is_empty_range(new_start, new_end) {
312 proxy.delete(old_start, old_end - old_start);
313 } else if is_empty_range(old_start, old_end) {
314 proxy.insert(old_start, new_start, new_end - new_start);
315 } else if let Some(MiddleSnakeResult {
316 d: _,
317 x_start,
318 y_start,
319 }) = find_middle_snake(
320 timeout_ms, start_time, old, old_start, old_end, new, new_start, new_end, vf, vb,
321 )? {
322 conquer(
323 proxy,
324 should_use_dj,
325 timeout_ms,
326 start_time,
327 old,
328 old_start,
329 x_start,
330 new,
331 new_start,
332 y_start,
333 vf,
334 vb,
335 )?;
336 conquer(
337 proxy,
338 should_use_dj,
339 timeout_ms,
340 start_time,
341 old,
342 x_start,
343 old_end,
344 new,
345 y_start,
346 new_end,
347 vf,
348 vb,
349 )?;
350 } else {
351 proxy.delete(old_start, old_end - old_start);
352 proxy.insert(old_start, new_start, new_end - new_start);
353 }
354 }
355
356 Ok(())
357}
358
359#[must_use]
361pub(crate) fn dj_diff<D: DiffHandler>(
362 proxy: &mut OperateProxy<D>,
363 old: &[u32],
364 new: &[u32],
365 old_offset: usize,
366 new_offset: usize,
367 max_try_count: usize,
368) -> bool {
369 let common_prefix_len = common_prefix(old, new);
370 let common_suffix_len = common_suffix_len(&old[common_prefix_len..], &new[common_prefix_len..]);
371 let old = &old[common_prefix_len..old.len() - common_suffix_len];
372 let new = &new[common_prefix_len..new.len() - common_suffix_len];
373 if old.len() >= u16::MAX as usize || new.len() >= u16::MAX as usize {
374 return false;
375 }
376
377 if old.is_empty() {
378 if new.is_empty() {
379 return true;
380 }
381
382 proxy.insert(
383 old_offset + common_prefix_len,
384 new_offset + common_prefix_len,
385 new.len(),
386 );
387 return true;
388 }
389
390 if new.is_empty() {
391 proxy.delete(old_offset + common_prefix_len, old.len());
392 return true;
393 }
394
395 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
396 struct Point {
397 x: u16,
398 y: u16,
399 }
400
401 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
402 enum Direction {
403 Up,
404 Left,
405 UpLeft,
406 }
407
408 struct QueueItem {
409 point: Point,
410 cost: u32,
411 from: Direction,
412 }
413
414 impl PartialEq for QueueItem {
415 fn eq(&self, other: &Self) -> bool {
416 self.cost == other.cost
417 }
418 }
419
420 impl PartialOrd for QueueItem {
421 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
422 Some(self.cmp(other))
423 }
424 }
425
426 impl Ord for QueueItem {
427 fn cmp(&self, other: &Self) -> Ordering {
428 other.cost.cmp(&self.cost)
429 }
430 }
431
432 impl Eq for QueueItem {}
433
434 let mut visited: FxHashMap<Point, Direction> = FxHashMap::default();
435 let mut q: BinaryHeap<QueueItem> = BinaryHeap::new();
436 q.push(QueueItem {
437 point: Point { x: 0, y: 0 },
438 cost: 0,
439 from: Direction::UpLeft,
440 });
441
442 while let Some(QueueItem { point, cost, from }) = q.pop() {
443 if visited.contains_key(&point) {
444 continue;
445 }
446
447 visited.insert(point, from);
448 if point.x == old.len() as u16 && point.y == new.len() as u16 {
449 break;
450 }
451
452 if visited.len() + q.len() > max_try_count {
453 return false;
456 }
457
458 if point.x < old.len() as u16 {
459 let next_point = Point {
460 x: point.x + 1,
461 y: point.y,
462 };
463
464 if !visited.contains_key(&next_point) {
465 let mut next_cost = cost + 1;
466 if from != Direction::Left {
467 next_cost += 8;
468 }
469
470 q.push(QueueItem {
471 point: next_point,
472 cost: next_cost,
473 from: Direction::Left,
474 });
475 }
476 }
477
478 if point.y < new.len() as u16 {
479 let next_point = Point {
480 x: point.x,
481 y: point.y + 1,
482 };
483
484 if !visited.contains_key(&next_point) {
485 let direction = Direction::Up;
486 let mut next_cost = cost + 1;
487 if from != direction {
488 next_cost += 8;
489 }
490
491 q.push(QueueItem {
492 point: next_point,
493 cost: next_cost,
494 from: Direction::Up,
495 });
496 }
497 }
498
499 if point.x < old.len() as u16
500 && point.y < new.len() as u16
501 && old[point.x as usize] == new[point.y as usize]
502 {
503 let next_point = Point {
504 x: point.x + 1,
505 y: point.y + 1,
506 };
507
508 if !visited.contains_key(&next_point) {
509 let next_cost = if from == Direction::UpLeft {
510 cost
511 } else {
512 cost + 1
513 };
514
515 q.push(QueueItem {
516 point: next_point,
517 cost: next_cost,
518 from: Direction::UpLeft,
519 });
520 }
521 }
522 }
523
524 let mut current = Point {
529 x: old.len() as u16,
530 y: new.len() as u16,
531 };
532
533 let mut path: Vec<(Direction, usize)> = Vec::new();
534 while current.x > 0 || current.y > 0 {
535 let direction = visited.get(¤t).unwrap();
536 if let Some((last_dir, count)) = path.last_mut() {
537 if last_dir == direction {
538 *count += 1;
539 } else {
540 path.push((*direction, 1));
541 }
542 } else {
543 path.push((*direction, 1));
544 }
545 match direction {
546 Direction::Left => {
547 current.x -= 1;
548 }
549 Direction::Up => {
550 current.y -= 1;
551 }
552 Direction::UpLeft => {
553 current.x -= 1;
554 current.y -= 1;
555 }
556 }
557 }
558
559 path.reverse();
560
561 let mut old_index = common_prefix_len;
562 let mut new_index = common_prefix_len;
563
564 for (direction, count) in path {
565 match direction {
566 Direction::Left => {
567 proxy.delete(old_offset + old_index, count);
568 old_index += count;
569 }
570 Direction::Up => {
571 proxy.insert(old_offset + old_index, new_index + new_offset, count);
572 new_index += count;
573 }
574 Direction::UpLeft => {
575 old_index += count;
576 new_index += count;
577 }
578 }
579 }
580
581 true
582}
583
584#[cfg(test)]
585mod tests {
586 use super::*;
587
588 #[derive(Debug, Default)]
589 struct RecordingDiffHandler {
590 ops: Vec<DiffOperation>,
591 }
592
593 #[derive(Debug, PartialEq)]
594 enum DiffOperation {
595 Insert {
596 old_index: usize,
597 new_index: usize,
598 length: usize,
599 },
600 Delete {
601 old_index: usize,
602 length: usize,
603 },
604 }
605
606 impl DiffHandler for RecordingDiffHandler {
607 fn insert(&mut self, pos: usize, start: usize, len: usize) {
608 self.ops.push(DiffOperation::Insert {
609 old_index: pos,
610 new_index: start,
611 length: len,
612 });
613 }
614
615 fn delete(&mut self, pos: usize, len: usize) {
616 self.ops.push(DiffOperation::Delete {
617 old_index: pos,
618 length: len,
619 });
620 }
621 }
622
623 #[test]
624 fn test_recording_diff_handler() {
625 let handler = RecordingDiffHandler::default();
626 let mut proxy = OperateProxy::new(handler);
627 let old = vec![1, 2, 3];
628 let new = vec![1, 4, 3];
629
630 let _ = dj_diff(&mut proxy, &old, &new, 0, 0, 100_000);
631 let handler = proxy.unwrap();
632 assert_eq!(
633 handler.ops,
634 vec![
635 DiffOperation::Delete {
636 old_index: 1,
637 length: 1
638 },
639 DiffOperation::Insert {
640 old_index: 2,
641 new_index: 1,
642 length: 1
643 },
644 ]
645 );
646 }
647
648 #[test]
649 fn test_dj_diff_same() {
650 let handler = RecordingDiffHandler::default();
651 let mut proxy = OperateProxy::new(handler);
652 let old = vec![1, 2, 3];
653 let new = vec![1, 2, 3];
654 let _ = dj_diff(&mut proxy, &old, &new, 0, 0, 100_000);
655 let handler = proxy.unwrap();
656 assert_eq!(handler.ops, vec![]);
657 }
658
659 #[test]
660 fn test_dj_diff_1() {
661 let handler = RecordingDiffHandler::default();
662 let mut proxy = OperateProxy::new(handler);
663 let old = vec![1];
664 let new = vec![0, 1, 2];
665 let _ = dj_diff(&mut proxy, &old, &new, 0, 0, 100_000);
666 let handler = proxy.unwrap();
667 assert_eq!(
668 handler.ops,
669 vec![
670 DiffOperation::Insert {
671 old_index: 0,
672 new_index: 0,
673 length: 1
674 },
675 DiffOperation::Insert {
676 old_index: 1,
677 new_index: 2,
678 length: 1
679 },
680 ]
681 );
682 }
683
684 #[test]
685 fn test_diff_may_scatter() {
686 let handler = RecordingDiffHandler::default();
687 let mut proxy = OperateProxy::new(handler);
688 let old = vec![1, 2, 3, 4, 5];
689 let new = vec![99, 1, 2, 3, 4, 5, 98, 97, 96, 3, 95, 4, 93, 92, 5, 91];
690 diff(&mut proxy, UpdateOptions::default(), &old, &new).unwrap();
691 let handler = proxy.unwrap();
692 assert_eq!(
693 handler.ops,
694 vec![
695 DiffOperation::Insert {
696 old_index: 0,
697 new_index: 0,
698 length: 1
699 },
700 DiffOperation::Insert {
701 old_index: 5,
702 new_index: 6,
703 length: 10
704 },
705 ]
706 );
707 }
708
709 #[test]
710 fn test_diff_may_scatter_1() {
711 let handler = RecordingDiffHandler::default();
712 let mut proxy = OperateProxy::new(handler);
713 let old = vec![1, 2, 3, 4, 5];
714 let new = vec![99, 1, 2, 98, 97, 96, 3, 95, 4, 93, 92, 5, 1, 2, 3, 4, 5, 91];
715 diff(&mut proxy, UpdateOptions::default(), &old, &new).unwrap();
716 let handler = proxy.unwrap();
717 assert_eq!(
718 handler.ops,
719 vec![
720 DiffOperation::Insert {
721 old_index: 0,
722 new_index: 0,
723 length: 12
724 },
725 DiffOperation::Insert {
726 old_index: 5,
727 new_index: 17,
728 length: 1
729 },
730 ]
731 );
732 }
733
734 #[test]
735 fn test_dj_diff_may_scatter() {
736 let handler = RecordingDiffHandler::default();
737 let mut proxy = OperateProxy::new(handler);
738 let old = vec![1, 2, 3, 4, 5];
739 let new = vec![99, 1, 2, 3, 4, 5, 98, 97, 96, 3, 95, 4, 93, 92, 5, 91];
740 let _ = dj_diff(&mut proxy, &old, &new, 0, 0, 100_000);
741 let handler = proxy.unwrap();
742 assert_eq!(
743 handler.ops,
744 vec![
745 DiffOperation::Insert {
746 old_index: 0,
747 new_index: 0,
748 length: 1
749 },
750 DiffOperation::Insert {
751 old_index: 5,
752 new_index: 6,
753 length: 10
754 },
755 ]
756 );
757 }
758
759 #[test]
760 fn test_dj_diff_may_scatter_1() {
761 let handler = RecordingDiffHandler::default();
762 let mut proxy = OperateProxy::new(handler);
763 let old = vec![1, 2, 3, 4, 5];
764 let new = vec![99, 1, 2, 98, 97, 96, 3, 95, 4, 93, 92, 5, 1, 2, 3, 4, 5, 91];
765 let _ = dj_diff(&mut proxy, &old, &new, 0, 0, 100_000);
766 let handler = proxy.unwrap();
767 assert_eq!(
768 handler.ops,
769 vec![
770 DiffOperation::Insert {
771 old_index: 0,
772 new_index: 0,
773 length: 12
774 },
775 DiffOperation::Insert {
776 old_index: 5,
777 new_index: 17,
778 length: 1
779 },
780 ]
781 );
782 }
783
784 #[test]
785 fn test_dj_diff_100_differences() {
786 let handler = RecordingDiffHandler::default();
787 let mut proxy = OperateProxy::new(handler);
788 let old = vec![1; 100];
789 let new = vec![2; 100];
790 let _ = dj_diff(&mut proxy, &old, &new, 0, 0, 100_000);
791 let handler = proxy.unwrap();
792 assert_eq!(
793 handler.ops,
794 vec![
795 DiffOperation::Delete {
796 old_index: 0,
797 length: 100
798 },
799 DiffOperation::Insert {
800 old_index: 100,
801 new_index: 0,
802 length: 100
803 },
804 ]
805 );
806 }
807
808 #[test]
809 fn test_dj_diff_insert() {
810 let handler = RecordingDiffHandler::default();
811 let mut proxy = OperateProxy::new(handler);
812 let old = vec![1; 100];
813 let mut new = old.clone();
814 new.splice(50..50, [1, 2, 3, 4, 1, 2, 3, 4]);
815 new.splice(0..0, [0, 1, 2, 3, 4, 5, 6, 7]);
816 let _ = dj_diff(&mut proxy, &old, &new, 0, 0, 100_000);
817 let handler = proxy.unwrap();
818 assert_eq!(
819 handler.ops,
820 vec![
821 DiffOperation::Insert {
822 old_index: 0,
823 new_index: 0,
824 length: 9
825 },
826 DiffOperation::Insert {
827 old_index: 50,
828 new_index: 59,
829 length: 7
830 }
831 ]
832 );
833 }
834
835 #[test]
836 fn test_diff() {
837 let handler = RecordingDiffHandler::default();
838 let mut proxy = OperateProxy::new(handler);
839 let old = vec![1; 100];
840 let new = vec![2; 100];
841 diff(&mut proxy, Default::default(), &old, &new).unwrap();
842 }
843
844 #[test]
845 fn test_timeout() {
846 let handler = RecordingDiffHandler::default();
847 let mut proxy = OperateProxy::new(handler);
848 let old = vec![1; 10000];
849 let new = vec![2; 10000];
850 let options = UpdateOptions {
851 timeout_ms: Some(0.1),
852 ..Default::default()
853 };
854 let result = diff(&mut proxy, options, &old, &new);
855 assert!(result.is_err());
856 }
857}