RangeComparatorLCS::getDifferences()   D
last analyzed

Complexity

Conditions 20
Paths 66

Size

Total Lines 90
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 50
CRAP Score 20.1627

Importance

Changes 0
Metric Value
cc 20
eloc 55
nc 66
nop 0
dl 0
loc 90
ccs 50
cts 54
cp 0.9259
crap 20.1627
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * (c) Steve Nebes <[email protected]>
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
declare(strict_types=1);
10
11
namespace SN\DaisyDiff\RangeDifferencer;
12
13
use SN\DaisyDiff\RangeDifferencer\Core\LCS;
14
use SN\DaisyDiff\RangeDifferencer\Core\LCSSettings;
15
16
/**
17
 * Longest Common Subsequence RangeComparator
18
 */
19
class RangeComparatorLCS extends LCS
20
{
21
    /** @var RangeComparatorInterface */
22
    private $comparator1;
23
24
    /** @var RangeComparatorInterface */
25
    private $comparator2;
26
27
    /** @var int[][] */
28
    private $lcs = [];
29
30
    /**
31
     * @param RangeComparatorInterface $comparator1
32
     * @param RangeComparatorInterface $comparator2
33
     */
34 21
    public function __construct(RangeComparatorInterface $comparator1, RangeComparatorInterface $comparator2)
35
    {
36 21
        $this->comparator1 = $comparator1;
37 21
        $this->comparator2 = $comparator2;
38 21
    }
39
40
    /**
41
     * @param RangeComparatorInterface $left
42
     * @param RangeComparatorInterface $right
43
     * @param LCSSettings              $settings
44
     * @return RangeDifference[]
45
     */
46 11
    public static function findDifferences(
47
        RangeComparatorInterface $left,
48
        RangeComparatorInterface $right,
49
        LCSSettings $settings
50
    ): array {
51 11
        $lcs = new static($left, $right);
52 11
        $lcs->longestCommonSubsequence($settings);
53
54 11
        return $lcs->getDifferences();
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60 15
    public function getLength1(): int
61
    {
62 15
        return $this->comparator1->getRangeCount();
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68 15
    public function getLength2(): int
69
    {
70 15
        return $this->comparator2->getRangeCount();
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76 13
    protected function initializeLcs(int $lcsLength): void
77
    {
78 13
        $this->lcs = \array_fill(0, 2, \array_fill(0, $lcsLength, 0));
79 13
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84 12
    protected function isRangeEqual(int $i1, int $i2): bool
85
    {
86 12
        return $this->comparator1->rangesEqual($i1, $this->comparator2, $i2);
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92 11
    protected function setLcs(int $sl1, int $sl2): void
93
    {
94
        // Add one to the values so that 0 can mean that the slot is empty.
95 11
        $this->lcs[0][$sl1] = $sl1 + 1;
96 11
        $this->lcs[1][$sl1] = $sl2 + 1;
97 11
    }
98
99
    /**
100
     * @return RangeDifference[]
101
     */
102 14
    public function getDifferences(): array
103
    {
104 14
        $differences = [];
105 14
        $length = $this->getLength();
106
107 14
        if (0 === $length) {
108 3
            $differences[] = new RangeDifference(
109 3
                RangeDifference::CHANGE,
110 3
                0, $this->comparator2->getRangeCount(),
111 3
                0, $this->comparator1->getRangeCount());
112
        } else {
113 11
            $index1 = 0;
114 11
            $index2 = 0;
115 11
            $s1 = -1;
116 11
            $s2 = -1;
117
118 11
            while ($index1 < \count($this->lcs[0]) && $index2 < \count($this->lcs[1])) {
119
                // Move both LCS lists to the next occupied slot.
120 11
                while (0 === ($l1 = $this->lcs[0][$index1])) {
121 8
                    $index1++;
122
123 8
                    if ($index1 >= \count($this->lcs[0])) {
124
                        break;
125
                    }
126
                }
127
128 11
                if ($index1 >= \count($this->lcs[0])) {
129
                    break;
130
                }
131
132 11
                while (0 === ($l2 = $this->lcs[1][$index2])) {
133 8
                    $index2++;
134
135 8
                    if ($index2 >= \count($this->lcs[1])) {
136
                        break;
137
                    }
138
                }
139
140 11
                if ($index2 >= \count($this->lcs[1])) {
141
                    break;
142
                }
143
144
                // Convert the entry to an array index (see setLcs(int, int)).
145 11
                $end1 = $l1 - 1;
146 11
                $end2 = $l2 - 1;
147
148 11
                if (-1 === $s1 && (0 !== $end1 || 0 !== $end2)) {
149
                    // There is a diff at the beginning.
150
                    // TODO: We need to confirm that this is the proper order.
151 2
                    $differences[] = new RangeDifference(
152 2
                        RangeDifference::CHANGE,
153 2
                        0, $end2,
154 2
                        0, $end1);
155 10
                } elseif ($end1 !== $s1 + 1 || $end2 !== $s2 + 1) {
156
                    // A diff was found on one of the sides.
157 8
                    $leftStart = $s1 + 1;
158 8
                    $leftLength = $end1 - $leftStart;
159 8
                    $rightStart = $s2 + 1;
160 8
                    $rightLength = $end2 - $rightStart;
161
162
                    // TODO: We need to confirm that this is the proper order.
163 8
                    $differences[] = new RangeDifference(
164 8
                        RangeDifference::CHANGE,
165 8
                        $rightStart, $rightLength,
166 8
                        $leftStart, $leftLength);
167
                }
168
169 11
                $s1 = $end1;
170 11
                $s2 = $end2;
171 11
                $index1++;
172 11
                $index2++;
173
            }
174
175
            if (
176 11
                -1 !== $s1 &&
177 11
                ($s1 + 1 < $this->comparator1->getRangeCount() || $s2 + 1 < $this->comparator2->getRangeCount())
178
            ) {
179
                // TODO: we need to find the proper way of representing an append.
180 1
                $leftStart = $s1 < $this->comparator1->getRangeCount() ? $s1 + 1 : $s1;
181 1
                $rightStart = $s2 < $this->comparator2->getRangeCount() ? $s2 + 1 : $s2;
182
183
                // TODO: We need to confirm that this is the proper order.
184 1
                $differences[] = new RangeDifference(
185 1
                    RangeDifference::CHANGE,
186 1
                    $rightStart, $this->comparator2->getRangeCount() - ($s2 + 1),
187 1
                    $leftStart, $this->comparator1->getRangeCount() - ($s1 + 1));
188
            }
189
        }
190
191 14
        return $differences;
192
    }
193
}
194