Merge introduce-meyer2

This commit is contained in:
wumpz
2017-04-13 08:47:09 +02:00
7 changed files with 102 additions and 150 deletions

View File

@@ -38,7 +38,9 @@ public interface DiffAlgorithm<T> {
* @param revised The revised sequence. Must not be {@code null}.
* @return The patch representing the diff of the given sequences. Never {@code null}.
*/
public Patch<T> diff(T[] original, T[] revised) throws DiffException;
public default Patch<T> diff(T[] original, T[] revised) throws DiffException {
return diff(Arrays.asList(original), Arrays.asList(revised));
}
/**
* Computes the difference between the original sequence and the revised sequence and returns it

View File

@@ -1,62 +0,0 @@
/*-
* #%L
* java-diff-utils
* %%
* Copyright (C) 2009 - 2017 java-diff-utils
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
* #L%
*/
package difflib.algorithm.myers;
/**
* A diffnode in a diffpath.
* <p>
* A DiffNode and its previous node mark a delta between two input sequences, that is, two differing
* subsequences between (possibly zero length) matching sequences.
*
* {@link DiffNode DiffNodes} and {@link Snake Snakes} allow for compression of diffpaths, as each
* snake is represented by a single {@link Snake Snake} node and each contiguous series of
* insertions and deletions is represented by a single {@link DiffNode DiffNodes}.
*
* @author <a href="mailto:juanco@suigeneris.org">Juanco Anez</a>
*
*/
public final class DiffNode extends PathNode {
/**
* Constructs a DiffNode.
* <p>
* DiffNodes are compressed. That means that the path pointed to by the <code>prev</code>
* parameter will be followed using {@link PathNode#previousSnake} until a non-diff node is
* found.
*
* @param the position in the original sequence
* @param the position in the revised sequence
* @param prev the previous node in the path.
*/
public DiffNode(int i, int j, PathNode prev) {
super(i, j, (prev == null ? null : prev.previousSnake()));
}
/**
* {@inheritDoc}
*
* @return false, always
*/
@Override
public boolean isSnake() {
return false;
}
}

View File

@@ -74,16 +74,6 @@ public final class MyersDiff<T> implements DiffAlgorithm<T> {
this.equalizer = equalizer;
}
/**
* {@inheritDoc}
*
* @return Returns an empty diff if get the error while procession the difference.
*/
@Override
public Patch<T> diff(final T[] original, final T[] revised) throws DiffException {
return diff(Arrays.asList(original), Arrays.asList(revised));
}
/**
* {@inheritDoc}
*
@@ -93,7 +83,7 @@ public final class MyersDiff<T> implements DiffAlgorithm<T> {
public Patch<T> diff(final List<T> original, final List<T> revised) throws DiffException {
Objects.requireNonNull(original, "original list must not be null");
Objects.requireNonNull(revised, "revised list must not be null");
PathNode path = buildPath(original, revised);
return buildRevision(path, original, revised);
}
@@ -121,7 +111,7 @@ public final class MyersDiff<T> implements DiffAlgorithm<T> {
final int middle = size / 2;
final PathNode diagonal[] = new PathNode[size];
diagonal[middle + 1] = new Snake(0, -1, null);
diagonal[middle + 1] = new PathNode(0, -1, true, true, null);
for (int d = 0; d < MAX; d++) {
for (int k = -d; k <= d; k += 2) {
final int kmiddle = middle + k;
@@ -142,17 +132,15 @@ public final class MyersDiff<T> implements DiffAlgorithm<T> {
int j = i - k;
PathNode node = new DiffNode(i, j, prev);
PathNode node = new PathNode(i, j, false, false, prev);
// orig and rev are zero-based
// but the algorithm is one-based
// that's why there's no +1 when indexing the sequences
while (i < N && j < M && equalizer.equals(orig.get(i), rev.get(j))) {
i++;
j++;
}
if (i > node.i) {
node = new Snake(i, j, node);
if (i != node.i) {
node = new PathNode(i, j, true, false, node);
}
diagonal[kmiddle] = node;
@@ -162,7 +150,6 @@ public final class MyersDiff<T> implements DiffAlgorithm<T> {
}
}
diagonal[middle + d - 1] = null;
}
// According to Myers, this cannot happen
throw new DifferentiationFailedException("could not find a diff path");

View File

@@ -22,13 +22,13 @@ package difflib.algorithm.myers;
/**
* A node in a diffpath.
*
* @author <a href="mailto:juanco@suigeneris.org">Juanco Anez</a>
* @author <a href="mailto:juanco@suigeneris.org">Juanco Anez</a>
*
* @see DiffNode
* @see Snake
*
*/
public abstract class PathNode {
public final class PathNode {
/**
* Position in the original sequence.
@@ -43,6 +43,10 @@ public abstract class PathNode {
*/
public final PathNode prev;
public final boolean snake;
public final boolean bootstrap;
/**
* Concatenates a new path node with an existing diffpath.
*
@@ -50,18 +54,21 @@ public abstract class PathNode {
* @param j The position in the revised sequence for the new node.
* @param prev The previous node in the path.
*/
public PathNode(int i, int j, PathNode prev) {
public PathNode(int i, int j, boolean snake, boolean bootstrap, PathNode prev) {
this.i = i;
this.j = j;
this.prev = prev;
this.bootstrap = bootstrap;
if (snake) {
this.prev = prev;
} else {
this.prev = (prev == null ? null : prev.previousSnake());
}
this.snake = snake;
}
/**
* Is this node a {@link Snake Snake node}?
*
* @return true if this is a {@link Snake Snake node}
*/
public abstract boolean isSnake();
public boolean isSnake() {
return snake;
}
/**
* Is this a bootstrap node?
@@ -71,7 +78,7 @@ public abstract class PathNode {
* @return tru if this is a bootstrap node.
*/
public boolean isBootstrap() {
return i < 0 || j < 0;
return bootstrap;
}
/**

View File

@@ -1,56 +0,0 @@
/*-
* #%L
* java-diff-utils
* %%
* Copyright (C) 2009 - 2017 java-diff-utils
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
* #L%
*/
package difflib.algorithm.myers;
/**
* Represents a snake in a diffpath.
* <p>
*
* {@link DiffNode DiffNodes} and {@link Snake Snakes} allow for compression of diffpaths, as each
* snake is represented by a single {@link Snake Snake} node and each contiguous series of
* insertions and deletions is represented by a single {@link DiffNode DiffNodes}.
*
* @author <a href="mailto:juanco@suigeneris.org">Juanco Anez</a>
*
*/
public final class Snake extends PathNode {
/**
* Constructs a snake node.
*
* @param the position in the original sequence
* @param the position in the revised sequence
* @param prev the previous node in the path.
*/
public Snake(int i, int j, PathNode prev) {
super(i, j, prev);
}
/**
* {@inheritDoc}
*
* @return true always
*/
@Override
public boolean isSnake() {
return true;
}
}

View File

@@ -145,11 +145,19 @@ public class DiffUtilsTest {
assertEquals(1, patch.getDeltas().size());
}
private static List<String> readStringListFromInputStream(InputStream is) throws IOException {
public static List<String> readStringListFromInputStream(InputStream is) throws IOException {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(is, Charset.forName(StandardCharsets.UTF_8.name())))) {
return reader.lines().collect(toList());
}
}
@Test
public void testDiffMyersExample1() throws DiffException {
final Patch<String> patch = DiffUtils.diff(Arrays.asList("A","B","C","A","B","B","A"), Arrays.asList("C","B","A","B","A","C"));
assertNotNull(patch);
assertEquals(4, patch.getDeltas().size());
assertEquals("Patch{deltas=[[DeleteDelta, position: 0, lines: [A, B]], [InsertDelta, position: 3, lines: [B]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2017 java-diff-utils.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package difflib.algorithm.myers;
import difflib.DiffUtils;
import difflib.algorithm.DiffException;
import difflib.patch.Patch;
import java.util.Arrays;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author tw
*/
public class MyersDiffTest {
public MyersDiffTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
@Test
public void testDiffMyersExample1Forward() throws DiffException {
final Patch<String> patch = new MyersDiff<String>().diff(
Arrays.asList("A","B","C","A","B","B","A"),
Arrays.asList("C","B","A","B","A","C"));
assertNotNull(patch);
assertEquals(4, patch.getDeltas().size());
assertEquals("Patch{deltas=[[DeleteDelta, position: 0, lines: [A, B]], [InsertDelta, position: 3, lines: [B]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
}
}