1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.text.diff; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 22 /** 23 * This class handles sequences of replacements resulting from a comparison. 24 * <p> 25 * The comparison of two objects sequences leads to the identification of common 26 * parts and parts which only belong to the first or to the second sequence. The 27 * common parts appear in the edit script in the form of <em>keep</em> commands, 28 * they can be considered as synchronization objects between the two sequences. 29 * These synchronization objects split the two sequences in synchronized 30 * sub-sequences. The first sequence can be transformed into the second one by 31 * replacing each synchronized sub-sequence of the first sequence by the 32 * corresponding sub-sequence of the second sequence. This is a synthetic way to 33 * see an {@link EditScript edit script}, replacing individual 34 * {@link DeleteCommand delete}, {@link KeepCommand keep} and 35 * {@link InsertCommand insert} commands by fewer replacements acting on 36 * complete sub-sequences. 37 * </p> 38 * <p> 39 * This class is devoted to perform this interpretation. It visits an 40 * {@link EditScript edit script} (because it implements the 41 * {@link CommandVisitor CommandVisitor} interface) and calls a user-supplied 42 * handler implementing the {@link ReplacementsHandler ReplacementsHandler} 43 * interface to process the sub-sequences. 44 * </p> 45 * 46 * @see ReplacementsHandler 47 * @see EditScript 48 * @see StringsComparator 49 * @param <T> object type 50 * @since 1.0 51 */ 52 public class ReplacementsFinder<T> implements CommandVisitor<T> { 53 54 /** 55 * List of pending insertions. 56 */ 57 private final List<T> pendingInsertions; 58 59 /** 60 * List of pending deletions. 61 */ 62 private final List<T> pendingDeletions; 63 64 /** 65 * Count of elements skipped. 66 */ 67 private int skipped; 68 69 /** Handler to call when synchronized sequences are found. */ 70 private final ReplacementsHandler<T> handler; 71 72 /** 73 * Constructs a new instance of {@link ReplacementsFinder}. 74 * 75 * @param handler handler to call when synchronized sequences are found 76 */ 77 public ReplacementsFinder(final ReplacementsHandler<T> handler) { 78 pendingInsertions = new ArrayList<>(); 79 pendingDeletions = new ArrayList<>(); 80 skipped = 0; 81 this.handler = handler; 82 } 83 84 /** 85 * Add an object to the pending deletions set. 86 * 87 * @param object object to delete 88 */ 89 @Override 90 public void visitDeleteCommand(final T object) { 91 pendingDeletions.add(object); 92 } 93 94 /** 95 * Add an object to the pending insertions set. 96 * 97 * @param object object to insert 98 */ 99 @Override 100 public void visitInsertCommand(final T object) { 101 pendingInsertions.add(object); 102 } 103 104 /** 105 * Handle a synchronization object. 106 * <p> 107 * When a synchronization object is identified, the pending insertions and 108 * pending deletions sets are provided to the user handler as subsequences. 109 * </p> 110 * 111 * @param object synchronization object detected 112 */ 113 @Override 114 public void visitKeepCommand(final T object) { 115 if (pendingDeletions.isEmpty() && pendingInsertions.isEmpty()) { 116 ++skipped; 117 } else { 118 handler.handleReplacement(skipped, pendingDeletions, pendingInsertions); 119 pendingDeletions.clear(); 120 pendingInsertions.clear(); 121 skipped = 1; 122 } 123 } 124 125 }