File Coverage

blib/lib/Text/Diff3/Diff3.pm
Criterion Covered Total %
statement 69 75 92.0
branch 22 26 84.6
condition 6 9 66.6
subroutine 7 7 100.0
pod 1 1 100.0
total 105 118 88.9


line stmt bran cond sub pod time code
1             package Text::Diff3::Diff3;
2             # diff3 component
3 6     6   89 use 5.006;
  6         18  
  6         233  
4 6     6   45 use strict;
  6         19  
  6         179  
5 6     6   32 use warnings;
  6         16  
  6         201  
6              
7 6     6   29 use base qw(Text::Diff3::Base);
  6         12  
  6         49  
8              
9 6     6   833 use version; our $VERSION = '0.08';
  6         11  
  6         21  
10              
11             # the three-way diff procedure based on the GNU diff3.c by Randy Smith.
12             sub diff3 {
13 21     21 1 34 my($self, $text0, $text2, $text1) = @_;
14 21         50 my $f = $self->factory;
15 21 50       52 if (! $self->_is_a_text($text0)) {
16 0         0 $text0 = $f->create_text($text0);
17             }
18 21 50       44 if (! $self->_is_a_text($text2)) {
19 0         0 $text0 = $f->create_text($text2);
20             }
21 21 50       40 if (! $self->_is_a_text($text1)) {
22 0         0 $text0 = $f->create_text($text1);
23             }
24 21         72 my $diffp = $f->create_diff;
25 21         59 my @diff2 = (
26             $diffp->diff($text2, $text0),
27             $diffp->diff($text2, $text1),
28             );
29 21         66 my $diff3 = $f->create_list3;
30 21         67 my $range3 = $f->create_null_range3;
31 21   66     65 while (! $diff2[0]->is_empty || ! $diff2[1]->is_empty) {
32             # find a continual range in text2 $lo2..$hi2
33             # changed by text0 or by text1.
34             #
35             # diff2[0] 222 222222222
36             # text2 ...L!!!!!!!!!!!!!!!!!!!!H...
37             # diff2[1] 222222 22 2222222
38 33         83 my @range2 = ([], []);
39 33 100       82 my $i =
    100          
    100          
40             $diff2[0]->is_empty ? 1
41             : $diff2[1]->is_empty ? 0
42             : $diff2[0]->first->loA <= $diff2[1]->first->loA ? 0
43             : 1;
44 33         51 my $j = $i;
45 33         36 my $k = $i ^ 1;
46 33         87 my $hi = $diff2[$j]->first->hiA;
47 33         39 push @{$range2[$j]}, $diff2[$j]->shift;
  33         88  
48 33   100     90 while (! $diff2[$k]->is_empty && $diff2[$k]->first->loA <= $hi + 1) {
49 10         31 my $hi_k = $diff2[$k]->first->hiA;
50 10         13 push @{$range2[$k]}, $diff2[$k]->shift;
  10         26  
51 10 50       37 if ($hi < $hi_k) {
52 0         0 $hi = $hi_k;
53 0         0 $j = $k;
54 0         0 $k = $k ^ 1;
55             }
56             }
57 33         109 my $lo2 = $range2[$i][ 0]->loA;
58 33         96 my $hi2 = $range2[$j][-1]->hiA;
59             # take the corresponding ranges in text0 $lo0..$hi0
60             # and in text1 $lo1..$hi1.
61             #
62             # text0 ..L!!!!!!!!!!!!!!!!!!!!!!!!!!!!H...
63             # diff2[0] 222 222222222
64             # text2 ...00!1111!000!!00!111111...
65             # diff2[1] 222222 22 2222222
66             # text1 ...L!!!!!!!!!!!!!!!!H...
67 33         36 my($lo0, $hi0);
68 33 100       31 if (@{$range2[0]}) {
  33         97  
69 21         55 $lo0 = $range2[0][ 0]->loB - $range2[0][ 0]->loA + $lo2;
70 21         53 $hi0 = $range2[0][-1]->hiB - $range2[0][-1]->hiA + $hi2;
71             } else {
72 12         32 $lo0 = $range3->hi0 - $range3->hi2 + $lo2;
73 12         30 $hi0 = $range3->hi0 - $range3->hi2 + $hi2;
74             }
75 33         38 my($lo1, $hi1);
76 33 100       28 if (@{$range2[1]}) {
  33         68  
77 22         58 $lo1 = $range2[1][ 0]->loB - $range2[1][ 0]->loA + $lo2;
78 22         60 $hi1 = $range2[1][-1]->hiB - $range2[1][-1]->hiA + $hi2;
79             } else {
80 11         30 $lo1 = $range3->hi1 - $range3->hi2 + $lo2;
81 11         31 $hi1 = $range3->hi1 - $range3->hi2 + $hi2;
82             }
83 33         112 $range3 = $f->create_range3(
84             undef, $lo0, $hi0, $lo1, $hi1, $lo2, $hi2
85             );
86             # detect type of changes.
87 33 100       83 if (! @{$range2[0]}) {
  33 100       61  
  21 100       52  
88 12         29 $range3->type('1');
89             } elsif (! @{$range2[1]}) {
90 11         30 $range3->type('0');
91             } elsif ($hi0 - $lo0 != $hi1 - $lo1) {
92 2         7 $range3->type('A');
93             } else {
94 8         19 $range3->type('2');
95 8         18 for my $d (0 .. $hi0 - $lo0) {
96 13 100       33 if (! $text0->eq_at($lo0 + $d, $text1->at($lo1 + $d))) {
97 2         6 $range3->type('A');
98 2         3 last;
99             }
100             }
101             }
102 33         80 $diff3->push($range3);
103             }
104 21         138 return $diff3;
105             }
106              
107             sub _is_a_text {
108 63     63   67 my($self, $x) = @_;
109 63   33     61 return eval{ $x->can('at') } && eval{ $x->can('eq_at') };
110             }
111              
112             1;
113              
114             __END__