/// ================================================================================
/// CAPTURE DIFF HOOK ALGORITHM
/// ================================================================================
///
/// The Capture algorithm is a simple but essential component that collects
/// all diff operations as they are generated by other algorithms.
///
/// ALGORITHM OVERVIEW:
/// 1. Collects all operations (Equal, Delete, Insert, Replace) in sequence
/// 2. Provides methods to access collected operations
/// 3. Sorts operations for consistent ordering
/// 4. Acts as a foundation for testing and debugging diff algorithms
///
/// DESIGN PATTERN: Observer pattern - captures operations without processing
/// TIME COMPLEXITY: O(1) per operation, O(N log N) for final sorting
/// SPACE COMPLEXITY: O(N) where N is the number of operations
///| ================================================================================
/// CAPTURE STRUCTURE
/// ================================================================================
///
/// A simple wrapper around Array[DiffOp] that implements the DiffHook interface
/// This allows it to collect operations from any diff algorithm
type Capture Array[DiffOp] derive(Default)
/// ================================================================================
/// CONSTRUCTION METHODS
/// ================================================================================
///| Creates a new empty Capture hook
///
/// @return New Capture instance ready to collect operations
pub fn Capture::new() -> Capture {
Capture::default()
}
///| Consumes the Capture hook and returns the collected operations
///
/// @return Array of all captured diff operations
pub fn Capture::into_ops(self : Capture) -> Array[DiffOp] {
self.inner()
}
///| Returns an iterator over the captured operations
///
/// @return Iterator yielding each captured operation in order
pub fn Capture::to_iter(self : Capture) -> Iter[DiffOp] {
self.inner().iter()
}
///| Returns a reference to the captured operations without consuming
///
/// @return Reference to the underlying operations array
pub fn Capture::ops(self : Capture) -> Array[DiffOp] {
self.inner()
}
/// ================================================================================
/// DIFF HOOK IMPLEMENTATION
/// ================================================================================
///
/// These methods implement the DiffHook interface to collect operations
/// Each method simply appends the operation to the internal array
///| Captures an Equal operation indicating unchanged content
///
/// @param old_index Starting index in old sequence
/// @param new_index Starting index in new sequence
/// @param len Number of equal elements
pub impl DiffHook for Capture with equal(
self : Capture,
old_index : Int,
new_index : Int,
len : Int,
) -> Result[Unit, Error] {
self.inner().push(DiffOp::Equal(old_index~, new_index~, len~))
Ok(())
}
///| Captures a Delete operation indicating removed content
///
/// @param old_index Starting index in old sequence
/// @param old_len Number of deleted elements
/// @param new_index Position in new sequence where deletion occurred
pub impl DiffHook for Capture with delete(
self : Capture,
old_index : Int,
old_len : Int,
new_index : Int,
) -> Result[Unit, Error] {
self.inner().push(DiffOp::Delete(old_index~, old_len~, new_index~))
Ok(())
}
///| Captures an Insert operation indicating added content
///
/// @param old_index Position in old sequence where insertion occurred
/// @param new_index Starting index in new sequence
/// @param new_len Number of inserted elements
pub impl DiffHook for Capture with insert(
self : Capture,
old_index : Int,
new_index : Int,
new_len : Int,
) -> Result[Unit, Error] {
self.inner().push(DiffOp::Insert(old_index~, new_index~, new_len~))
Ok(())
}
///| Captures a Replace operation indicating changed content
///
/// @param old_index Starting index in old sequence
/// @param old_len Number of elements replaced
/// @param new_index Starting index in new sequence
/// @param new_len Number of replacement elements
pub impl DiffHook for Capture with replace(
self : Capture,
old_index : Int,
old_len : Int,
new_index : Int,
new_len : Int,
) -> Result[Unit, Error] {
self.inner().push(DiffOp::Replace(old_index~, old_len~, new_index~, new_len~))
Ok(())
}
///| Final processing step - sorts operations for consistent output
///
/// ALGORITHM: Sorts operations by old sequence position, then new sequence position
/// This ensures deterministic output regardless of algorithm execution order
pub impl DiffHook for Capture with finish(self : Capture) -> Result[Unit, Error] {
self.sort()
Ok(())
}
///| ================================================================================
/// SORTING ALGORITHM
/// ================================================================================
///
/// Sorts captured operations to ensure consistent and predictable output
///
/// SORTING STRATEGY:
/// 1. Primary sort key: position in old sequence (ascending)
/// 2. Secondary sort key: position in new sequence (ascending)
/// 3. Tertiary rule: Delete operations come before other operations at same position
///
/// This ordering produces diffs that read naturally from top to bottom
pub fn Capture::sort(self : Capture) -> Unit {
/// Helper function to extract sorting keys from operations
fn get_old_new_index(op : DiffOp) -> (Int, Int)? {
match op {
DiffOp::Equal(old_index~, new_index~, len=_) =>
Some((old_index, new_index))
DiffOp::Delete(old_index~, old_len=_, new_index~) =>
Some((old_index, new_index))
DiffOp::Insert(old_index~, new_index~, new_len=_) =>
Some((old_index, new_index))
DiffOp::Replace(old_index~, old_len=_, new_index~, new_len=_) =>
Some((old_index, new_index))
}
}
// Apply stable sorting with defined ordering rules
self
.inner()
.sort_by(fn(a : DiffOp, b : DiffOp) -> Int {
let (a_old, a_new) = get_old_new_index(a).unwrap()
let (b_old, b_new) = get_old_new_index(b).unwrap()
if a_old == b_old {
// When old positions match, apply secondary sorting rules
// Delete operations should come before other operations for consistency
match (a, b) {
(Delete(..), Delete(..)) => a_new - b_new
(Delete(..), _) => -1
(_, Delete(..)) => 1
_ => a_new - b_new
}
} else {
// Primary sort by old sequence position
a_old - b_old
}
})
}