GeezerVison is showing github.com — attached logging to new meyer diff algorithm · GronwD/java-diff-utils@c765616
File treeExpand file treeCollapse file tree Open diff view settings main/java/com/github/difflib test/java/com/github/difflib/algorithm/myers
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: java-diff-utils/src/main/java/com/github/difflib/DiffUtils.java +41-30Lines changed: 41 additions & 30 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 15 | 15 | */ | 16 | 16 | package com.github.difflib; | 17 | 17 |
| | 18 | +import com.github.difflib.algorithm.DiffAlgorithmFactory; | 18 | 19 | import com.github.difflib.algorithm.DiffAlgorithmI; | 19 | 20 | import com.github.difflib.algorithm.DiffAlgorithmListener; | 20 | | -import com.github.difflib.algorithm.myers.MyersDiff; | | 21 | +import com.github.difflib.algorithm.myers.MeyersDiff; | 21 | 22 | import com.github.difflib.patch.AbstractDelta; | 22 | 23 | import com.github.difflib.patch.Patch; | 23 | 24 | import com.github.difflib.patch.PatchFailedException; | | 34 | 35 | public final class DiffUtils { | 35 | 36 |
| 36 | 37 | /** | 37 | | - * Computes the difference between the original and revised list of elements with default diff | 38 | | - * algorithm | | 38 | + * This factory generates the DEFAULT_DIFF algorithm for all these routines. | | 39 | + */ | | 40 | + static DiffAlgorithmFactory DEFAULT_DIFF = MeyersDiff.factory(); | | 41 | + | | 42 | + public static void withDefaultDiffAlgorithmFactory(DiffAlgorithmFactory factory) { | | 43 | + DEFAULT_DIFF = factory; | | 44 | + } | | 45 | + | | 46 | + /** | | 47 | + * Computes the difference between the original and revised list of elements | | 48 | + * with default diff algorithm | 39 | 49 | * | 40 | 50 | * @param <T> types to be diffed | 41 | 51 | * @param original The original text. Must not be {@code null}. | 42 | 52 | * @param revised The revised text. Must not be {@code null}. | 43 | 53 | * @param progress progress listener | 44 | | - * @return The patch describing the difference between the original and revised sequences. Never | 45 | | - * {@code null}. | | 54 | + * @return The patch describing the difference between the original and | | 55 | + * revised sequences. Never {@code null}. | 46 | 56 | */ | 47 | 57 | public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmListener progress) { | 48 | | - return DiffUtils.diff(original, revised, new MyersDiff<>(), progress); | | 58 | + return DiffUtils.diff(original, revised, DEFAULT_DIFF.create(), progress); | 49 | 59 | } | 50 | 60 |
| 51 | 61 | public static <T> Patch<T> diff(List<T> original, List<T> revised) { | 52 | | - return DiffUtils.diff(original, revised, new MyersDiff<>(), null); | | 62 | + return DiffUtils.diff(original, revised, DEFAULT_DIFF.create(), null); | 53 | 63 | } | 54 | | - | | 64 | + | 55 | 65 | public static <T> Patch<T> diff(List<T> original, List<T> revised, boolean includeEqualParts) { | 56 | | - return DiffUtils.diff(original, revised, new MyersDiff<>(), null, includeEqualParts); | | 66 | + return DiffUtils.diff(original, revised, DEFAULT_DIFF.create(), null, includeEqualParts); | 57 | 67 | } | 58 | 68 |
| 59 | 69 | /** | @@ -67,45 +77,46 @@ public static Patch<String> diff(String sourceText, String targetText, | 67 | 77 | } | 68 | 78 |
| 69 | 79 | /** | 70 | | - * Computes the difference between the original and revised list of elements with default diff | 71 | | - * algorithm | | 80 | + * Computes the difference between the original and revised list of elements | | 81 | + * with default diff algorithm | 72 | 82 | * | 73 | 83 | * @param source The original text. Must not be {@code null}. | 74 | 84 | * @param target The revised text. Must not be {@code null}. | 75 | 85 | * | 76 | | - * @param equalizer the equalizer object to replace the default compare algorithm | 77 | | - * (Object.equals). If {@code null} the default equalizer of the default algorithm is used.. | 78 | | - * @return The patch describing the difference between the original and revised sequences. Never | 79 | | - * {@code null}. | | 86 | + * @param equalizer the equalizer object to replace the default compare | | 87 | + * algorithm (Object.equals). If {@code null} the default equalizer of the | | 88 | + * default algorithm is used.. | | 89 | + * @return The patch describing the difference between the original and | | 90 | + * revised sequences. Never {@code null}. | 80 | 91 | */ | 81 | 92 | public static <T> Patch<T> diff(List<T> source, List<T> target, | 82 | 93 | BiPredicate<T, T> equalizer) { | 83 | 94 | if (equalizer != null) { | 84 | 95 | return DiffUtils.diff(source, target, | 85 | | - new MyersDiff<>(equalizer)); | | 96 | + DEFAULT_DIFF.create(equalizer)); | 86 | 97 | } | 87 | | - return DiffUtils.diff(source, target, new MyersDiff<>()); | | 98 | + return DiffUtils.diff(source, target, new MeyersDiff<>()); | 88 | 99 | } | 89 | 100 |
| 90 | 101 | public static <T> Patch<T> diff(List<T> original, List<T> revised, | 91 | 102 | DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress) { | 92 | 103 | return diff(original, revised, algorithm, progress, false); | 93 | 104 | } | 94 | | - | | 105 | + | 95 | 106 | /** | 96 | | - * Computes the difference between the original and revised list of elements with default diff | 97 | | - * algorithm | | 107 | + * Computes the difference between the original and revised list of elements | | 108 | + * with default diff algorithm | 98 | 109 | * | 99 | 110 | * @param original The original text. Must not be {@code null}. | 100 | 111 | * @param revised The revised text. Must not be {@code null}. | 101 | 112 | * @param algorithm The diff algorithm. Must not be {@code null}. | 102 | 113 | * @param progress The diff algorithm listener. | 103 | 114 | * @param includeEqualParts Include equal data parts into the patch. | 104 | | - * @return The patch describing the difference between the original and revised sequences. Never | 105 | | - * {@code null}. | | 115 | + * @return The patch describing the difference between the original and | | 116 | + * revised sequences. Never {@code null}. | 106 | 117 | */ | 107 | 118 | public static <T> Patch<T> diff(List<T> original, List<T> revised, | 108 | | - DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress, | | 119 | + DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress, | 109 | 120 | boolean includeEqualParts) { | 110 | 121 | Objects.requireNonNull(original, "original must not be null"); | 111 | 122 | Objects.requireNonNull(revised, "revised must not be null"); | @@ -115,23 +126,23 @@ public static <T> Patch<T> diff(List<T> original, List<T> revised, | 115 | 126 | } | 116 | 127 |
| 117 | 128 | /** | 118 | | - * Computes the difference between the original and revised list of elements with default diff | 119 | | - * algorithm | | 129 | + * Computes the difference between the original and revised list of elements | | 130 | + * with default diff algorithm | 120 | 131 | * | 121 | 132 | * @param original The original text. Must not be {@code null}. | 122 | 133 | * @param revised The revised text. Must not be {@code null}. | 123 | 134 | * @param algorithm The diff algorithm. Must not be {@code null}. | 124 | | - * @return The patch describing the difference between the original and revised sequences. Never | 125 | | - * {@code null}. | | 135 | + * @return The patch describing the difference between the original and | | 136 | + * revised sequences. Never {@code null}. | 126 | 137 | */ | 127 | 138 | public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmI<T> algorithm) { | 128 | 139 | return diff(original, revised, algorithm, null); | 129 | 140 | } | 130 | 141 |
| 131 | 142 | /** | 132 | | - * Computes the difference between the given texts inline. This one uses the "trick" to make out | 133 | | - * of texts lists of characters, like DiffRowGenerator does and merges those changes at the end | 134 | | - * together again. | | 143 | + * Computes the difference between the given texts inline. This one uses the | | 144 | + * "trick" to make out of texts lists of characters, like DiffRowGenerator | | 145 | + * does and merges those changes at the end together again. | 135 | 146 | * | 136 | 147 | * @param original | 137 | 148 | * @param revised | |
Collapse file Copy file name to clipboard +29Lines changed: 29 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +/* | | 2 | + * Copyright 2021 java-diff-utils. | | 3 | + * | | 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | | 5 | + * you may not use this file except in compliance with the License. | | 6 | + * You may obtain a copy of the License at | | 7 | + * | | 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | | 9 | + * | | 10 | + * Unless required by applicable law or agreed to in writing, software | | 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | | 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | | 13 | + * See the License for the specific language governing permissions and | | 14 | + * limitations under the License. | | 15 | + */ | | 16 | +package com.github.difflib.algorithm; | | 17 | + | | 18 | +import java.util.function.BiPredicate; | | 19 | + | | 20 | +/** | | 21 | + * Tool to create new instances of a diff algorithm. This one is only needed at the moment to | | 22 | + * set DiffUtils default diff algorithm. | | 23 | + * @author tw | | 24 | + */ | | 25 | +public interface DiffAlgorithmFactory { | | 26 | + <T> DiffAlgorithmI<T> create(); | | 27 | + | | 28 | + <T> DiffAlgorithmI<T> create(BiPredicate<T, T> equalizer); | | 29 | +} |
Collapse file Copy file name to clipboardExpand all lines: java-diff-utils/src/main/java/com/github/difflib/algorithm/myers/MeyersDiff.java +29-8Lines changed: 29 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 16 | 16 | package com.github.difflib.algorithm.myers; | 17 | 17 |
| 18 | 18 | import com.github.difflib.algorithm.Change; | | 19 | +import com.github.difflib.algorithm.DiffAlgorithmFactory; | 19 | 20 | import com.github.difflib.algorithm.DiffAlgorithmI; | 20 | 21 | import com.github.difflib.algorithm.DiffAlgorithmListener; | 21 | 22 | import com.github.difflib.patch.DeltaType; | | 26 | 27 | import java.util.function.BiPredicate; | 27 | 28 |
| 28 | 29 | /** | 29 | | - * A clean-room implementation of Eugene Myers greedy differencing algorithm. | | 30 | + * A clean-room implementation of Eugene Meyers greedy differencing algorithm. | 30 | 31 | */ | 31 | | -public final class MyersDiff<T> implements DiffAlgorithmI<T> { | | 32 | +public final class MeyersDiff<T> implements DiffAlgorithmI<T> { | 32 | 33 |
| 33 | 34 | private final BiPredicate<T, T> equalizer; | 34 | 35 |
| 35 | | - public MyersDiff() { | | 36 | + public MeyersDiff() { | 36 | 37 | equalizer = Object::equals; | 37 | 38 | } | 38 | 39 |
| 39 | | - public MyersDiff(final BiPredicate<T, T> equalizer) { | | 40 | + public MeyersDiff(final BiPredicate<T, T> equalizer) { | 40 | 41 | Objects.requireNonNull(equalizer, "equalizer must not be null"); | 41 | 42 | this.equalizer = equalizer; | 42 | 43 | } | @@ -63,8 +64,9 @@ public List<Change> computeDiff(final List<T> source, final List<T> target, Diff | 63 | 64 | } | 64 | 65 |
| 65 | 66 | /** | 66 | | - * Computes the minimum diffpath that expresses de differences between the original and revised | 67 | | - * sequences, according to Gene Myers differencing algorithm. | | 67 | + * Computes the minimum diffpath that expresses de differences between the | | 68 | + * original and revised sequences, according to Gene Myers differencing | | 69 | + * algorithm. | 68 | 70 | * | 69 | 71 | * @param orig The original sequence. | 70 | 72 | * @param rev The revised sequence. | @@ -138,8 +140,8 @@ private PathNode buildPath(final List<T> orig, final List<T> rev, DiffAlgorithmL | 138 | 140 | * @param orig The original sequence. | 139 | 141 | * @param rev The revised sequence. | 140 | 142 | * @return A {@link Patch} script corresponding to the path. | 141 | | - * @throws DifferentiationFailedException if a {@link Patch} could not be built from the given | 142 | | - * path. | | 143 | + * @throws DifferentiationFailedException if a {@link Patch} could not be | | 144 | + * built from the given path. | 143 | 145 | */ | 144 | 146 | private List<Change> buildRevision(PathNode actualPath, List<T> orig, List<T> rev) { | 145 | 147 | Objects.requireNonNull(actualPath, "path is null"); | @@ -176,4 +178,23 @@ private List<Change> buildRevision(PathNode actualPath, List<T> orig, List<T> re | 176 | 178 | } | 177 | 179 | return changes; | 178 | 180 | } | | 181 | + | | 182 | + /** | | 183 | + * Factory to create instances of this specific diff algorithm. | | 184 | + */ | | 185 | + public static DiffAlgorithmFactory factory() { | | 186 | + return new DiffAlgorithmFactory() { | | 187 | + @Override | | 188 | + public <T> DiffAlgorithmI<T> | | 189 | + create() { | | 190 | + return new MeyersDiff<T>(); | | 191 | + } | | 192 | + | | 193 | + @Override | | 194 | + public <T> DiffAlgorithmI<T> | | 195 | + create(BiPredicate < T, T > equalizer) { | | 196 | + return new MeyersDiff<T>(equalizer); | | 197 | + } | | 198 | + }; | | 199 | + } | 179 | 200 | } |
Collapse file Copy file name to clipboardExpand all lines: java-diff-utils/src/main/java/com/github/difflib/algorithm/myers/MeyersDiffWithLinearSpace.java +28-7Lines changed: 28 additions & 7 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 23 | 23 | import java.util.List; | 24 | 24 | import java.util.Objects; | 25 | 25 | import java.util.function.BiPredicate; | | 26 | +import java.util.function.Consumer; | 26 | 27 |
| 27 | 28 | /** | 28 | 29 | * | @@ -43,13 +44,33 @@ public MeyersDiffWithLinearSpace(final BiPredicate<T, T> equalizer) { | 43 | 44 |
| 44 | 45 | @Override | 45 | 46 | public List<Change> computeDiff(List<T> source, List<T> target, DiffAlgorithmListener progress) { | | 47 | + Objects.requireNonNull(source, "source list must not be null"); | | 48 | + Objects.requireNonNull(target, "target list must not be null"); | | 49 | + | | 50 | + if (progress != null) { | | 51 | + progress.diffStart(); | | 52 | + } | | 53 | + | 46 | 54 | DiffData data = new DiffData(source, target); | 47 | | - //shouldn't it be source.size() - 1? | 48 | | - buildScript(data, 0, source.size(), 0, target.size()); | | 55 | + | | 56 | + int maxIdx = source.size() + target.size(); | | 57 | + | | 58 | + buildScript(data, 0, source.size(), 0, target.size(), idx -> { | | 59 | + if (progress != null) { | | 60 | + progress.diffStep(idx, maxIdx); | | 61 | + } | | 62 | + }); | | 63 | + | | 64 | + if (progress != null) { | | 65 | + progress.diffEnd(); | | 66 | + } | 49 | 67 | return data.script; | 50 | 68 | } | 51 | 69 |
| 52 | | - private void buildScript(DiffData data, int start1, int end1, int start2, int end2) { | | 70 | + private void buildScript(DiffData data, int start1, int end1, int start2, int end2, Consumer<Integer> progress) { | | 71 | + if (progress != null) { | | 72 | + progress.accept(start1); | | 73 | + } | 53 | 74 | final Snake middle = getMiddleSnake(data, start1, end1, start2, end2); | 54 | 75 | if (middle == null | 55 | 76 | || middle.start == end1 && middle.diag == end1 - end2 | @@ -86,8 +107,8 @@ private void buildScript(DiffData data, int start1, int end1, int start2, int en | 86 | 107 | } | 87 | 108 | } | 88 | 109 | } else { | 89 | | - buildScript(data, start1, middle.start, start2, middle.start - middle.diag); | 90 | | - buildScript(data, middle.end, end1, middle.end - middle.diag, end2); | | 110 | + buildScript(data, start1, middle.start, start2, middle.start - middle.diag, progress); | | 111 | + buildScript(data, middle.end, end1, middle.end - middle.diag, end2, progress); | 91 | 112 | } | 92 | 113 | } | 93 | 114 |
| @@ -169,7 +190,7 @@ private Snake buildSnake(DiffData data, final int start, final int diag, final i | 169 | 190 | return new Snake(start, end, diag); | 170 | 191 | } | 171 | 192 |
| 172 | | - class DiffData { | | 193 | + private class DiffData { | 173 | 194 |
| 174 | 195 | final int size; | 175 | 196 | final int[] vDown; | @@ -188,7 +209,7 @@ public DiffData(List<T> source, List<T> target) { | 188 | 209 | } | 189 | 210 | } | 190 | 211 |
| 191 | | - class Snake { | | 212 | + private class Snake { | 192 | 213 |
| 193 | 214 | final int start; | 194 | 215 | final int end; | |
Collapse file Copy file name to clipboardExpand all lines: java-diff-utils/src/test/java/com/github/difflib/algorithm/myers/MeyersDiffWithLinearSpaceTest.java +4-4Lines changed: 4 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -39,8 +39,8 @@ public void testDiffMyersExample1Forward() { | 39 | 39 | final Patch<String> patch = Patch.generate(original, revised, new MeyersDiffWithLinearSpace<String>().computeDiff(original, revised, null)); | 40 | 40 | assertNotNull(patch); | 41 | 41 | System.out.println(patch); | 42 | | - assertEquals(4, patch.getDeltas().size()); | 43 | | - 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()); | | 42 | + assertEquals(5, patch.getDeltas().size()); | | 43 | + assertEquals("Patch{deltas=[[InsertDelta, position: 0, lines: [C]], [DeleteDelta, position: 0, lines: [A]], [DeleteDelta, position: 2, lines: [C]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString()); | 44 | 44 | } | 45 | 45 |
| 46 | 46 | @Test | @@ -68,8 +68,8 @@ public void diffEnd() { | 68 | 68 | })); | 69 | 69 | assertNotNull(patch); | 70 | 70 | System.out.println(patch); | 71 | | - assertEquals(4, patch.getDeltas().size()); | 72 | | - 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()); | | 71 | + assertEquals(5, patch.getDeltas().size()); | | 72 | + assertEquals("Patch{deltas=[[InsertDelta, position: 0, lines: [C]], [DeleteDelta, position: 0, lines: [A]], [DeleteDelta, position: 2, lines: [C]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString()); | 73 | 73 | System.out.println(logdata); | 74 | 74 | assertEquals(8, logdata.size()); | 75 | 75 | } | |
Collapse file Copy file name to clipboardExpand all lines: java-diff-utils/src/test/java/com/github/difflib/algorithm/myers/MyersDiffTest.java +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -34,7 +34,7 @@ public class MyersDiffTest { | 34 | 34 | public void testDiffMyersExample1Forward() { | 35 | 35 | List<String> original = Arrays.asList("A", "B", "C", "A", "B", "B", "A"); | 36 | 36 | List<String> revised = Arrays.asList("C", "B", "A", "B", "A", "C"); | 37 | | - final Patch<String> patch = Patch.generate(original, revised, new MyersDiff<String>().computeDiff(original, revised, null)); | | 37 | + final Patch<String> patch = Patch.generate(original, revised, new MeyersDiff<String>().computeDiff(original, revised, null)); | 38 | 38 | assertNotNull(patch); | 39 | 39 | assertEquals(4, patch.getDeltas().size()); | 40 | 40 | 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()); | @@ -47,7 +47,7 @@ public void testDiffMyersExample1ForwardWithListener() { | 47 | 47 |
| 48 | 48 | List<String> logdata = new ArrayList<>(); | 49 | 49 | final Patch<String> patch = Patch.generate(original, revised, | 50 | | - new MyersDiff<String>().computeDiff(original, revised, new DiffAlgorithmListener() { | | 50 | + new MeyersDiff<String>().computeDiff(original, revised, new DiffAlgorithmListener() { | 51 | 51 | @Override | 52 | 52 | public void diffStart() { | 53 | 53 | logdata.add("start"); | |
|