Completed
Push — master ( 42324d...1863b6 )
by Steve
03:59 queued 02:04
created

TagDiffer::preProcess()   C

Complexity

Conditions 13
Paths 26

Size

Total Lines 53
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 35
nc 26
nop 2
dl 0
loc 53
rs 6.6166
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
declare(strict_types=1);
4
5
namespace SN\RangeDifferencer\Tag;
6
7
use Exception;
8
use SN\RangeDifferencer\RangeDifference;
9
use SN\RangeDifferencer\RangeDifferencer;
10
11
/**
12
 * Takes 2 AtomSplitters and computes the difference between them. Output is sent to a given HTMLSaxDiffOutput and tags
13
 * are diffed internally on a second iteration. The results are processed as to combine small subsequent changes in to
14
 * larger changes.
15
 */
16
class TagDiffer implements TextDifferInterface
0 ignored issues
show
Bug introduced by
The type SN\RangeDifferencer\Tag\TextDifferInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
{
18
    /** @var TextDiffOutputInterface */
0 ignored issues
show
Bug introduced by
The type SN\RangeDifferencer\Tag\TextDiffOutputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
    private $output;
20
21
    /**
22
     * @param TextDiffOutputInterface $output
23
     */
24
    public function __construct(TextDiffOutputInterface $output)
25
    {
26
        $this->output = $output;
27
    }
28
29
    /**
30
     * @param AtomSplitterInterface $leftComparator
31
     * @param AtomSplitterInterface $rightComparator
32
     * @throws Exception
33
     */
34
    public function diff(AtomSplitterInterface $leftComparator, AtomSplitterInterface $rightComparator): void
35
    {
36
        $differences  = RangeDifferencer::findDifferences($leftComparator, $rightComparator);
37
        $pDifferences = $this->preProcess($differences, $leftComparator);
38
39
        $rightAtom = 0;
40
        $leftAtom  = 0;
41
42
        for ($i = 0; $i < count($pDifferences); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
43
            $this->parseNoChange(
44
                $leftAtom, $pDifferences[$i]->leftStart(),
45
                $rightAtom, $pDifferences[$i]->rightStart(),
46
                $leftComparator, $rightComparator);
47
48
            $leftString  = $leftComparator->substring($pDifferences[$i]->leftStart(), $pDifferences[$i]->leftEnd());
49
            $rightString = $rightComparator->substring($pDifferences[$i]->rightStart(), $pDifferences[$i]->rightEnd());
50
51
            if ($pDifferences[$i]->leftLength() > 0) {
52
                $this->output->addRemovedPart($leftString);
53
            }
54
55
            if ($pDifferences[$i]->rightLength() > 0) {
56
                $this->output->addAddedPart($rightString);
57
            }
58
59
            $rightAtom = $pDifferences[$i]->rightEnd();
60
            $leftAtom  = $pDifferences[$i]->leftEnd();
61
        }
62
63
        if ($rightAtom < $rightComparator->getRangeCount()) {
64
            $this->parseNoChange(
65
                $leftAtom, $leftComparator->getRangeCount(),
66
                $rightAtom, $rightComparator->getRangeCount(),
67
                $leftComparator, $rightComparator);
68
        }
69
    }
70
71
    /**
72
     * @param int                   $beginLeft
73
     * @param int                   $endLeft
74
     * @param int                   $beginRight
75
     * @param int                   $endRight
76
     * @param AtomSplitterInterface $leftComparator
77
     * @param AtomSplitterInterface $rightComparator
78
     * @throws
79
     */
80
    private function parseNoChange(
81
        int $beginLeft,
82
        int $endLeft,
83
        int $beginRight,
84
        int $endRight,
85
        AtomSplitterInterface $leftComparator,
86
        AtomSplitterInterface $rightComparator
87
    ): void {
88
        assert($endRight);
89
90
        $s = '';
91
92
        // We can assume that the LCS is correct and that there are exactly as many atoms left and right.
93
        while ($beginLeft < $endLeft) {
94
            while ($beginLeft < $endLeft &&
95
                !$rightComparator->getAtom($beginRight)->hasInternalIdentifiers() &&
96
                !$leftComparator->getAtom($beginLeft)->hasInternalIdentifiers()) {
97
                $s .= $rightComparator->getAtom($beginRight)->getFullText();
98
                $beginRight++;
99
                $beginLeft++;
100
            }
101
102
            if (mb_strlen($s) > 0) {
103
                $this->output->addClearPart($s);
104
                $s = '';
105
            }
106
107
            if ($beginLeft < $endLeft) {
108
                $leftComparator2  = new ArgumentComparator($leftComparator->getAtom($beginLeft)->getFullText());
109
                $rightComparator2 = new ArgumentComparator($rightComparator->getAtom($beginRight)->getFullText());
110
111
                $differences2  = RangeDifferencer::findDifferences($leftComparator2, $rightComparator2);
112
                $pDifferences2 = $this->preProcess2($differences2, 2);
113
114
                $rightAtom2 = 0;
115
116
                for ($j = 0; $j < count($pDifferences2); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
117
                    if ($rightAtom2 < $pDifferences2[$j]->rightStart()) {
118
                        $this->output->addClearPart($rightComparator2->substring(
119
                            $rightAtom2,
120
                            $pDifferences2[$j]->rightStart()));
121
                    }
122
123
                    if ($pDifferences2[$j]->leftLength() > 0) {
124
                        $this->output->addRemovedPart($leftComparator2->substring(
125
                            $pDifferences2[$j]->leftStart(),
126
                            $pDifferences2[$j]->leftEnd()));
127
                    }
128
129
                    if ($pDifferences2[$j]->rightLength() > 0) {
130
                        $this->output->addAddedPart($rightComparator2->substring(
131
                            $pDifferences2[$j]->rightStart(),
132
                            $pDifferences2[$j]->rightEnd()));
133
                    }
134
135
                    $rightAtom2 = $pDifferences2[$j]->rightEnd();
136
                }
137
138
                if ($rightAtom2 < $rightComparator2->getRangeCount()) {
139
                    $this->output->addClearPart($rightComparator2->substring($rightAtom2));
140
                }
141
142
                $beginLeft++;
143
                $beginRight++;
144
            }
145
        }
146
    }
147
148
    /**
149
     * @param RangeDifference[]     $differences
150
     * @param AtomSplitterInterface $leftComparator
151
     * @return RangeDifference[]
152
     * @throws Exception
153
     */
154
    private function preProcess(array $differences, AtomSplitterInterface $leftComparator): array
155
    {
156
        $newRanges = [];
157
158
        for ($i = 0; $i < count($differences); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
159
            $leftStart  = $differences[$i]->leftStart();
0 ignored issues
show
Bug introduced by
The method leftStart() does not exist on SN\RangeDifferencer\RangeDifference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

159
            /** @scrutinizer ignore-call */ 
160
            $leftStart  = $differences[$i]->leftStart();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
160
            $leftEnd    = $differences[$i]->leftEnd();
0 ignored issues
show
Bug introduced by
The method leftEnd() does not exist on SN\RangeDifferencer\RangeDifference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

160
            /** @scrutinizer ignore-call */ 
161
            $leftEnd    = $differences[$i]->leftEnd();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
161
            $rightStart = $differences[$i]->rightStart();
0 ignored issues
show
Bug introduced by
The method rightStart() does not exist on SN\RangeDifferencer\RangeDifference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

161
            /** @scrutinizer ignore-call */ 
162
            $rightStart = $differences[$i]->rightStart();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
162
            $rightEnd   = $differences[$i]->rightEnd();
0 ignored issues
show
Bug introduced by
The method rightEnd() does not exist on SN\RangeDifferencer\RangeDifference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

162
            /** @scrutinizer ignore-call */ 
163
            $rightEnd   = $differences[$i]->rightEnd();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
163
            $kind       = $differences[$i]->kind();
0 ignored issues
show
Bug introduced by
The method kind() does not exist on SN\RangeDifferencer\RangeDifference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

163
            /** @scrutinizer ignore-call */ 
164
            $kind       = $differences[$i]->kind();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
164
            $temp       = $leftEnd;
165
            $connecting = true;
166
167
            while ($connecting && $i + 1 < count($differences) && $differences[$i + 1]->kind() == $kind) {
168
                $bridgeLength = 0;
169
                $numTokens    = max($leftEnd - $leftStart, $rightEnd - $rightStart);
170
171
                if ($numTokens > 5) {
172
                    if ($numTokens > 10) {
173
                        $bridgeLength = 3;
174
                    } else {
175
                        $bridgeLength = 2;
176
                    }
177
                }
178
179
                while ($temp < $differences[$i + 1]->leftStart() &&
180
                    ($leftComparator->getAtom($temp) instanceof DelimiterAtom || ($bridgeLength-- > 0))) {
181
                    $temp++;
182
                }
183
184
                if ($temp == $differences[$i + 1]->leftStart()) {
185
                    $leftEnd  = $differences[$i + 1]->leftEnd();
186
                    $rightEnd = $differences[$i + 1]->rightEnd();
187
                    $temp     = $leftEnd;
188
                    $i++;
189
                } else {
190
                    $connecting = false;
191
192
                    if (!$leftComparator->getAtom($temp) instanceof DelimiterAtom) {
193
                        if (0 == strcmp($leftComparator->getAtom($temp)->getFullText(), '')) {
194
                            throw new Exception('Space found.');
195
                        }
196
                    }
197
                }
198
            }
199
200
            $newRanges[] = new RangeDifference(
201
                $kind,
202
                $rightStart, $rightEnd - $rightStart,
203
                $leftStart, $leftEnd - $leftStart);
204
        }
205
206
        return $newRanges;
207
    }
208
209
    /**
210
     * @param RangeDifference[] $differences
211
     * @param int               $span
212
     * @return RangeDifference[]
213
     */
214
    private function preProcess2(array $differences, int $span): array
215
    {
216
        $newRanges = [];
217
218
        for ($i = 0; $i < count($differences); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
219
            $leftStart  = $differences[$i]->leftStart();
220
            $leftEnd    = $differences[$i]->leftEnd();
221
            $rightStart = $differences[$i]->rightStart();
222
            $rightEnd   = $differences[$i]->rightEnd();
223
            $kind       = $differences[$i]->kind();
224
225
            while ($i + 1 < count($differences) &&
226
                $differences[$i + 1]->kind() == $kind &&
227
                $differences[$i + 1]->leftStart() == $leftEnd + $span &&
228
                $differences[$i + 1]->rightStart() == $rightEnd + $span) {
229
                $leftEnd  = $differences[$i + 1]->leftEnd();
230
                $rightEnd = $differences[$i + 1]->rightEnd();
231
                $i++;
232
            }
233
234
            $newRanges[] = new RangeDifference(
235
                $kind,
236
                $rightStart, $rightEnd - $rightStart,
237
                $leftStart, $leftEnd - $leftStart);
238
        }
239
240
        return $newRanges;
241
    }
242
}
243