Completed
Push — master ( 96cbf3...9bcdfc )
by Steve
03:03 queued 01:23
created

RangeComparatorLCS::getDifferences()   D

Complexity

Conditions 20
Paths 66

Size

Total Lines 82
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

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