Sign in

    ruifeng/diff/algorithms does not have a README file

    DiffHook

    pub(open) trait DiffHook {
    equal(Self, old_index : Int, new_index : Int, len : Int) -> Result[Unit, Error] = _
    delete(Self, old_index : Int, old_len : Int, new_index : Int) -> Result[Unit, Error] = _
    insert(Self, old_index : Int, new_index : Int, new_len : Int) -> Result[Unit, Error] = _
    replace(Self, old_index : Int, old_len : Int, new_index : Int, new_len : Int) -> Result[Unit, Error] = _
    finish(Self) -> Result[Unit, Error] = _
    }
    Different hooks can be implemented to process or store the diff results.

    Capture

    type Capture

    ================================================================================ CAPTURE STRUCTURE

    A simple wrapper around Array[DiffOp] that implements the DiffHook interface This allows it to collect operations from any diff algorithm
    impl Default for Capture
    impl DiffHook for Capture

    Capture::into_ops

    fn Capture::into_ops(self : Capture) -> Array[DiffOp]
    Consumes the Capture hook and returns the collected operations

    @return Array of all captured diff operations

    Capture::new

    fn Capture::new() -> Capture
    Creates a new empty Capture hook

    @return New Capture instance ready to collect operations

    Capture::ops

    fn Capture::ops(self : Capture) -> Array[DiffOp]
    Returns a reference to the captured operations without consuming

    @return Reference to the underlying operations array

    Capture::sort

    fn Capture::sort(self : Capture) -> Unit

    ================================================================================ 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

    Capture::to_iter

    fn Capture::to_iter(self : Capture) -> Iter[DiffOp]
    Returns an iterator over the captured operations

    @return Iterator yielding each captured operation in order

    Compact

    pub(all) struct Compact[D, T] {
    d : D
    ops : Array[DiffOp]
    old : Array[T]
    new : Array[T]
    }

    ================================================================================ COMPACT DIFF STRUCTURE

    A diff hook that wraps another hook and performs compaction on the operations before passing them through.
    impl DiffHook for Compact[D, T]

    Compact::into_inner

    fn[D, T] Compact::into_inner(self : Compact[D, T]) -> D
    Consumes the Compact hook and returns the inner hook

    Compact::into_ops

    fn[D, T] Compact::into_ops(self : Compact[D, T]) -> Array[DiffOp]
    Returns collected operations (for testing purposes)

    Compact::new

    fn[D, T] Compact::new(d : D, old : Array[T], new : Array[T]) -> Compact[D, T]
    Creates a new Compact hook that wraps the provided diff hook

    Compact::sort

    fn[D, T] Compact::sort(self : Compact[D, T]) -> Unit

    ================================================================================ SORTING ALGORITHM

    Ensures consistent ordering of operations for predictable output Sorts primarily by old sequence position, secondarily by new sequence position

    DiffOp

    pub(all) enum DiffOp {
    Equal(Int, Int, Int)
    Delete(Int, Int, Int)
    Insert(Int, Int, Int)
    Replace(Int, Int, Int, Int)
    }
    Represents the different types of operations in a diff.
    impl Compare for DiffOp
    impl Eq for DiffOp
    impl Hash for DiffOp
    impl Show for DiffOp

    DiffOp::apply_to_hook

    fn[D : DiffHook] DiffOp::apply_to_hook(self : DiffOp, d : D) -> Result[Unit, Error]
    Applies the given DiffOp to a DiffHook.

    DiffOp::grow_left

    fn DiffOp::grow_left(self : DiffOp, adjust : Int) -> Unit
    Used by the Compact hook to merge operations.

    DiffOp::grow_right

    fn DiffOp::grow_right(self : DiffOp, adjust : Int) -> Unit
    Used by the Compact hook to merge operations.

    DiffOp::is_empty

    fn DiffOp::is_empty(self : DiffOp) -> Bool
    Checks if the operation is empty (i.e., has a length of zero).

    DiffOp::new_range

    fn DiffOp::new_range(self : DiffOp) -> Range
    Returns the range of the operation in the new sequence.

    DiffOp::old_range

    fn DiffOp::old_range(self : DiffOp) -> Range
    Returns the range of the operation in the old sequence.

    DiffOp::shift_left

    fn DiffOp::shift_left(self : DiffOp, adjust : Int) -> Unit
    Used by the Compact hook to merge operations.

    DiffOp::shift_right

    fn DiffOp::shift_right(self : DiffOp, adjust : Int) -> Unit
    Used by the Compact hook to merge operations.

    DiffOp::shrink_left

    fn DiffOp::shrink_left(self : DiffOp, adjust : Int) -> Unit
    Used by the Compact hook to merge operations.

    DiffOp::shrink_right

    fn DiffOp::shrink_right(self : DiffOp, adjust : Int) -> Unit
    Used by the Compact hook to merge operations.

    Myers

    pub type Myers
    The Myers diff algorithm implementation type

    Myers::diff

    fn[T : Eq, D : DiffHook] Myers::diff(d : D, old : Array[T], old_range : Range, new : Array[T], new_range : Range) -> Result[Unit, Error]

    ================================================================================ MAIN ALGORITHM ENTRY POINT

    Computes the diff between two sequences using Myers algorithm

    ALGORITHM STEPS:
    1. Initialize data structures (V vectors for forward/backward search)
    2. Use divide-and-conquer to recursively find optimal diffs
    3. Report results through the provided DiffHook

    NoFinishHook

    pub(all) struct NoFinishHook[D] {
    d : D
    }
    Useful for chaining hooks where only the outermost hook's finish should be called.

    NoFinishHook::into_inner

    fn[D] NoFinishHook::into_inner(self : NoFinishHook[D]) -> D
    Consumes the NoFinishHook and returns the inner hook.

    NoFinishHook::new

    fn[D] NoFinishHook::new(d : D) -> NoFinishHook[D]
    Creates a new NoFinishHook.

    Patience

    pub(all) struct Patience[T, D] {
    d : D
    old : Array[T]
    old_current : Int
    old_end : Int
    old_indexes : Array[UniqueItem[T]]
    new : Array[T]
    new_current : Int
    new_end : Int
    new_indexes : Array[UniqueItem[T]]
    }

    ================================================================================ PATIENCE DIFF STRUCTURE

    The Patience diff algorithm implementation that wraps another diff hook to provide enhanced human-readable diffs.

    Patience::diff

    fn[T : Eq + Hash, D : DiffHook] Patience::diff(d : D, old : Array[T], old_range : Range, new : Array[T], new_range : Range) -> Result[Unit, Error]

    ================================================================================ MAIN ALGORITHM ENTRY POINT

    Computes the diff using the Patience algorithm

    ALGORITHM STEPS:
    1. Extract unique items from both sequences
    2. Find LCS of unique items using Myers algorithm
    3. Use matching unique items as anchors for recursive diffing
    4. Apply Myers algorithm between anchors for detailed differences

    Range

    pub(all) struct Range {
    start : Int
    end : Int
    }

    ================================================================================ RANGE STRUCTURE

    Represents a contiguous range of indices [start, end) where:
    • start is inclusive (first index in range)
    • end is exclusive (one past the last index)

    This half-open interval design allows clean empty ranges (start == end) and simplifies length calculations (end - start)
    impl Show for Range

    Range::contains

    fn Range::contains(self : Range, i : Int) -> Bool
    Checks if a specific index falls within the range

    ALGORITHM: index is in range when start <= index < end This follows the half-open interval definition

    @param i The index to check @return true if index is within range, false otherwise

    Range::is_empty

    fn Range::is_empty(self : Range) -> Bool
    Checks if the range contains no elements

    ALGORITHM: A range is empty when start >= end This is the mathematical property of half-open intervals

    @return true if range contains no elements, false otherwise

    Range::iter

    fn Range::iter(self : Range) -> Iter[Int]

    ================================================================================ RANGE ITERATION ALGORITHM

    Creates an iterator over all indices in the range

    ALGORITHM: Generates indices from start to end-1 inclusive This provides a convenient way to iterate over array indices

    @return Iterator yielding all indices in the range

    Range::len

    fn Range::len(self : Range) -> Int
    Calculates the number of elements in the range

    ALGORITHM: length = max(0, end - start) The max ensures we never return negative length for invalid ranges

    @return Number of elements in the range (0 for empty ranges)

    Range::new

    fn Range::new(start : Int, end : Int) -> Range
    Creates a new Range with specified start and end indices

    @param start Inclusive start index @param end Exclusive end index @return New Range instance

    Replace

    pub(all) struct Replace[D] {
    d : D
    del : (Int, Int, Int)?
    ins : (Int, Int, Int)?
    eq : (Int, Int, Int)?
    }
    into a single Replace operation.
    impl DiffHook for Replace[D]

    Replace::flush_del_ins

    fn[D : DiffHook] Replace::flush_del_ins(self : Replace[D]) -> Result[Unit, Error]
    If both are present, they are merged into a Replace operation.

    Replace::flush_eq

    fn[D : DiffHook] Replace::flush_eq(self : Replace[D]) -> Result[Unit, Error]
    Flushes any pending Equal operation to the inner hook.

    Replace::into_inner

    fn[D] Replace::into_inner(self : Replace[D]) -> D
    Consumes the Replace hook and returns the inner hook.

    Replace::new

    fn[D] Replace::new(d : D) -> Replace[D]
    Creates a new Replace hook.

    UniqueItem

    type UniqueItem[T]
    Wrapper structure that associates an item with its original index Used to track positions after filtering unique items
    type V
    The V vector for tracking furthest-reaching paths in the edit graph

    V::len

    fn V::len(self : V) -> Int
    Returns the total capacity of the V vector

    V::new

    fn V::new(max_d : Int) -> V
    Creates a new V vector with capacity for diagonals from -max_d to +max_d

    V::op_get

    fn V::op_get(self : V, i : Int) -> Int
    Gets the x-coordinate for diagonal k

    V::op_set

    fn V::op_set(self : V, i : Int, value : Int) -> Unit
    Sets the x-coordinate for diagonal k

    cleanup_diff_ops

    fn[T : Eq] cleanup_diff_ops(old : Array[T], new : Array[T], ops : Array[DiffOp]) -> Unit
    Main compaction algorithm that coordinates the cleanup process

    STRATEGY:
    1. First pass: shift and merge delete operations
    2. Second pass: shift and merge insert operations
    3. Each pass applies both upward and downward shifts

    common_prefix_len

    fn[T : Eq] common_prefix_len(old : Array[T], old_range : Range, new : Array[T], new_range : Range) -> Int
    Calculates the length of the common prefix between two sequence ranges

    @param old First sequence array @param old_range Range within the first sequence @param new Second sequence array @param new_range Range within the second sequence @return Length of the common prefix (0 if no common prefix)

    common_suffix_len

    fn[T : Eq] common_suffix_len(old : Array[T], old_range : Range, new : Array[T], new_range : Range) -> Int
    Calculates the length of the common suffix between two sequence ranges

    @param old First sequence array @param old_range Range within the first sequence @param new Second sequence array @param new_range Range within the second sequence @return Length of the common suffix (0 if no common suffix)

    shift_diff_ops_down

    fn[T : Eq] shift_diff_ops_down(ops : Array[DiffOp], old : Array[T], new : Array[T], pointer : Int) -> Int
    Shifts operations downward (later) to merge with following operations

    Similar to shift_diff_ops_up but operates in the downward direction Uses common prefixes instead of suffixes for alignment

    shift_diff_ops_up

    fn[T : Eq] shift_diff_ops_up(ops : Array[DiffOp], old : Array[T], new : Array[T], pointer : Int) -> Int
    Shifts operations upward (earlier) to merge with previous operations

    SHIFTING RULES:
    1. Swap insert/delete operations to group similar operations
    2. Merge adjacent operations of the same type
    3. Align operations with common prefixes/suffixes
    4. Remove empty operations

    unique

    fn[T : Eq + Hash] unique(array : Array[T], range : Range) -> Array[UniqueItem[T]]
    Finds all unique items in a specified range of an array

    ALGORITHM STEPS:
    1. Build frequency map: count occurrences of each value
    2. Filter unique values: keep only items with count = 1
    3. Create tracking objects: wrap unique items with original indices
    4. Sort by position: maintain original sequence order

    @param array The source array to scan @param range The range within the array to examine @return Array of unique items with their original indices

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io