Algorithm-Merge
view release on metacpan or search on metacpan
$abc_s[(A|B)*8+B] = AB_B;
$abc_s[(A|C)*8+A] = AC_A;
$abc_s[(A|C)*8+C] = AC_C;
$abc_s[(B|C)*8+B] = BC_B;
$abc_s[(B|C)*8+C] = BC_C;
sub traverse_sequences3 {
my $adoc = shift; # array ref
my $bdoc = shift; # array ref
my $cdoc = shift; # array ref
my $callbacks = shift || {};
my $keyGen = shift;
my $a_diff = $callbacks->{'A_DIFF'} || sub { };
my $b_diff = $callbacks->{'B_DIFF'} || sub { };
my $c_diff = $callbacks->{'C_DIFF'} || sub { };
my $no_change = $callbacks->{'NO_CHANGE'} || sub { };
my $conflict = $callbacks->{'CONFLICT'} || sub { };
my $b_len = scalar(@{$bdoc});
my $c_len = scalar(@{$cdoc});
my $target_len = $b_len < $c_len ? $b_len : $c_len;
my $bc_different_lengths = $b_len != $c_len;
my(@bdoc_save, @cdoc_save);
# make these into traverse_sequences calls
my($left, $right);
my %diffs;
my $ts_callbacks = {
DISCARD_A => sub { # discard left
push @{$diffs{$left}}, $_[0];
},
DISCARD_B => sub { # discard right
push @{$diffs{$right}}, $_[1];
},
};
@diffs{(AB_A, AB_B)} = ([], []);
$left = AB_A; $right = AB_B;
Algorithm::Diff::traverse_sequences( $adoc, $bdoc, $ts_callbacks, $keyGen, @_);
@diffs{(AC_A, AC_C)} = ([], []);
$left = AC_A; $right = AC_C;
Algorithm::Diff::traverse_sequences( $adoc, $cdoc, $ts_callbacks, $keyGen, @_);
if($bc_different_lengths) {
@diffs{(CB_C, CB_B)} = ([], []);
$left = CB_C; $right = CB_B;
Algorithm::Diff::traverse_sequences( $cdoc, $bdoc, $ts_callbacks, $keyGen, @_);
@diffs{(BC_B, BC_C)} = ([], []);
$left = BC_B; $right = BC_C;
Algorithm::Diff::traverse_sequences( $bdoc, $cdoc, $ts_callbacks, $keyGen, @_);
if(join(",", @{$diffs{&CB_B}}) ne join(",", @{$diffs{&BC_B}}) ||
join(",", @{$diffs{&CB_C}}) ne join(",", @{$diffs{&BC_C}}))
{
@bdoc_save = splice @{$bdoc}, $target_len;
@cdoc_save = splice @{$cdoc}, $target_len;
carp "Algorithm::Diff::diff is not symmetric for second and third sequences - results might not be correct";
}
@diffs{(BC_B, BC_C)} = ([], []);
$left = BC_B; $right = BC_C;
Algorithm::Diff::traverse_sequences( $bdoc, $cdoc, $ts_callbacks, $keyGen, @_);
if(scalar(@bdoc_save) || scalar(@cdoc_save)) {
push @{$diffs{&BC_B}}, ($target_len .. $b_len) if $target_len < $b_len;
push @{$diffs{&BC_C}}, ($target_len .. $c_len) if $target_len < $c_len;
push @{$bdoc}, @bdoc_save; undef @bdoc_save;
push @{$cdoc}, @cdoc_save; undef @cdoc_save;
}
}
else {
@diffs{(BC_B, BC_C)} = ([], []);
$left = BC_B; $right = BC_C;
Algorithm::Diff::traverse_sequences( $bdoc, $cdoc, $ts_callbacks, $keyGen, @_);
}
my @pos;
@pos[A, B, C] = (0, 0, 0);
my @sizes;
@sizes[A, B, C] = ( scalar(@{$adoc}), scalar(@{$bdoc}), scalar(@{$cdoc}) );
my @matches;
$#matches = 32;
#main::diag(join"", " match: $match");
&{$Callback_Map[$switch][0]}(@args)
if $Callback_Map[$switch];
}
}
sub merge {
my $pivot = shift; # array ref
my $doca = shift; # array ref
my $docb = shift; # array ref
my $callbacks = shift || {};
my $keyGen = shift;
my $conflictCallback = $callbacks -> {'CONFLICT'} || sub ($$) { (
q{<!-- ------ START CONFLICT ------ -->},
(@{$_[0]}),
q{<!-- ---------------------------- -->},
(@{$_[1]}),
q{<!-- ------ END CONFLICT ------ -->},
) };
my $diff = diff3($pivot, $doca, $docb, $keyGen, @_);
# print Data::Dumper -> Dump([$diff]), "\n";
@diff = diff3(\@ancestor, \@a, \@b);
@diff = diff3(\@ancestor, \@a, \@b, $key_generation_function);
$diff = diff3(\@ancestor, \@a, \@b);
$diff = diff3(\@ancestor, \@a, \@b, $key_generation_function);
@trav = traverse_sequences3(\@ancestor, \@a, \@b, {
# callbacks
});
@trav = traverse_sequences3(\@ancestor, \@a, \@b, {
# callbacks
}, $key_generation_function);
$trav = traverse_sequences3(\@ancestor, \@a, \@b, {
# callbacks
});
$trav = traverse_sequences3(\@ancestor, \@a, \@b, {
# callbacks
}, $key_generation_function);
=head1 USAGE
This module complements L<Algorithm::Diff|Algorithm::Diff> by
providing three-way merge and diff functions.
In this documentation, the first list to C<diff3>, C<merge>, and
C<traverse_sequences3> is
(@left),
q{<!-- ---------------------------- -->},
(@right),
q{<!-- ------ END CONFLICT ------ -->},
=head2 traverse_sequences3
This is the workhorse function that goes through the three sequences
and calls the callback functions.
The following callbacks are supported.
=over 4
=item NO_CHANGE
This is called if all three sequences have the same element at the
current position. The arguments are the current positions within each
sequence, the first argument being the current position within the
first sequence.
@diff = diff3(\@ancestor, \@a, \@b);
@diff = diff3(\@ancestor, \@a, \@b, $key_generation_function);
$diff = diff3(\@ancestor, \@a, \@b);
$diff = diff3(\@ancestor, \@a, \@b, $key_generation_function);
@trav = traverse_sequences3(\@ancestor, \@a, \@b, {
# callbacks
});
@trav = traverse_sequences3(\@ancestor, \@a, \@b, {
# callbacks
}, $key_generation_function);
$trav = traverse_sequences3(\@ancestor, \@a, \@b, {
# callbacks
});
$trav = traverse_sequences3(\@ancestor, \@a, \@b, {
# callbacks
}, $key_generation_function);
USAGE
This module complements Algorithm::Diff by providing three-way merge and
diff functions.
In this documentation, the first list to "diff3", "merge", and
"traverse_sequences3" is called the `original' list. The second list is
the `left' list. The third list is the `right' list.
q{<!-- ------ START CONFLICT ------ -->},
(@left),
q{<!-- ---------------------------- -->},
(@right),
q{<!-- ------ END CONFLICT ------ -->},
traverse_sequences3
This is the workhorse function that goes through the three sequences and
calls the callback functions.
The following callbacks are supported.
NO_CHANGE
This is called if all three sequences have the same element at the
current position. The arguments are the current positions within
each sequence, the first argument being the current position within
the first sequence.
A_DIFF
This is called if the first sequence is different than the other two
sequences at the current position. This callback will be called with
( run in 0.876 second using v1.01-cache-2.11-cpan-10033ea8487 )