Use loop instead of iter

This commit is contained in:
Andras Schmelczer 2025-06-14 14:24:48 +01:00
commit 44697164a0
No known key found for this signature in database
GPG key ID: FC8F2C3D3D1A718C
2 changed files with 73 additions and 70 deletions

View file

@ -3,6 +3,7 @@ mod edited_text;
mod merge_context; mod merge_context;
mod operation; mod operation;
mod ordered_operation; mod ordered_operation;
mod utils;
pub use cursor::{CursorPosition, TextWithCursors}; pub use cursor::{CursorPosition, TextWithCursors};
pub use edited_text::EditedText; pub use edited_text::EditedText;

View file

@ -9,7 +9,7 @@ use crate::{
utils::{cook_operations::cook_operations, elongate_operations::elongate_operations}, utils::{cook_operations::cook_operations, elongate_operations::elongate_operations},
}, },
tokenizer::{Tokenizer, word_tokenizer::word_tokenizer}, tokenizer::{Tokenizer, word_tokenizer::word_tokenizer},
utils::{merge_iters::MergeSorted as _, side::Side, string_builder::StringBuilder}, utils::{side::Side, string_builder::StringBuilder},
}; };
/// A text document and a sequence of operations that can be applied to the text /// A text document and a sequence of operations that can be applied to the text
@ -117,82 +117,84 @@ where
let mut left_cursors = self.cursors.into_iter().peekable(); let mut left_cursors = self.cursors.into_iter().peekable();
let mut right_cursors = other.cursors.into_iter().peekable(); let mut right_cursors = other.cursors.into_iter().peekable();
let merged_operations: Vec<OrderedOperation<T>> = self let mut merged_operations: Vec<OrderedOperation<T>> =
.operations Vec::with_capacity(self.operations.len() + other.operations.len());
.into_iter()
// The current text is always the left; the other operation is the right side.
.map(|op| (op, Side::Left))
.merge_sorted_by_key(
other.operations.into_iter().map(|op| (op, Side::Right)),
|(operation, _)| {
(
operation.order,
operation.operation.start_index(),
// Make sure that the ordering is deterministic regardless which text
// is left or right.
match &operation.operation {
Operation::Equal { index, .. } => index.to_string(),
Operation::Insert { text, .. } => text
.iter()
.map(crate::tokenizer::token::Token::original)
.collect::<String>(),
Operation::Delete {
deleted_character_count,
..
} => deleted_character_count.to_string(),
},
)
},
)
.flat_map(|(OrderedOperation { order, operation }, side)| {
let original_start = operation.start_index() as i64;
let original_end = operation.end_index();
let original_length = operation.len() as i64;
let result = match side { let mut left_iter = self.operations.into_iter();
Side::Left => operation.merge_operations_with_context( let mut right_iter = other.operations.into_iter();
&mut right_merge_context,
&mut left_merge_context, let mut maybe_left_op = left_iter.next();
), let mut maybe_right_op = right_iter.next();
Side::Right => operation.merge_operations_with_context(
&mut left_merge_context, loop {
&mut right_merge_context, let (side, OrderedOperation { operation, order }) =
), match (maybe_left_op.clone(), maybe_right_op.clone()) {
(Some(left_op), Some(right_op)) => {
if left_op < right_op {
(Side::Left, left_op)
} else {
(Side::Right, right_op)
}
}
(Some(left_op), None) => (Side::Left, left_op),
(None, Some(right_op)) => (Side::Right, right_op),
(None, None) => break,
}; };
if let Some(ref op @ (Operation::Insert { .. } | Operation::Equal { .. })) = result if side == Side::Left {
{ maybe_left_op = left_iter.next();
let shift = op.start_index() as i64 - original_start + op.len() as i64 } else {
- original_length; maybe_right_op = right_iter.next();
match side { }
Side::Left => {
while let Some(cursor) = let original_start = operation.start_index() as i64;
left_cursors.next_if(|cursor| cursor.char_index <= original_end + 1) let original_end = operation.end_index();
{ let original_length = operation.len() as i64;
merged_cursors.push(cursor.with_index(
(op.start_index() as i64).max(cursor.char_index as i64 + shift) let result = match side {
as usize, Side::Left => operation.merge_operations_with_context(
)); &mut right_merge_context,
} &mut left_merge_context,
),
Side::Right => operation.merge_operations_with_context(
&mut left_merge_context,
&mut right_merge_context,
),
};
if let Some(ref op @ (Operation::Insert { .. } | Operation::Equal { .. })) = result {
let shift =
op.start_index() as i64 - original_start + op.len() as i64 - original_length;
match side {
Side::Left => {
while let Some(cursor) =
left_cursors.next_if(|cursor| cursor.char_index <= original_end + 1)
{
merged_cursors.push(cursor.with_index(
(op.start_index() as i64).max(cursor.char_index as i64 + shift)
as usize,
));
} }
Side::Right => { }
while let Some(cursor) = right_cursors Side::Right => {
.next_if(|cursor| cursor.char_index <= original_end + 1) while let Some(cursor) =
{ right_cursors.next_if(|cursor| cursor.char_index <= original_end + 1)
merged_cursors.push(cursor.with_index( {
(op.start_index() as i64).max(cursor.char_index as i64 + shift) merged_cursors.push(cursor.with_index(
as usize, (op.start_index() as i64).max(cursor.char_index as i64 + shift)
)); as usize,
} ));
} }
} }
} }
}
result merged_operations.extend(result.into_iter().map(|op| OrderedOperation {
.map(|operation| OrderedOperation { order, operation }) order,
.into_iter() operation: op,
}) }));
.collect(); }
let last_index = merged_operations let last_index = merged_operations
.iter() .iter()