View Javadoc
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   *
50   * @param <T> object type
51   * @since 1.0
52   */
53  public class ReplacementsFinder<T> implements CommandVisitor<T> {
54  
55      /**
56       * List of pending insertions.
57       */
58      private final List<T> pendingInsertions;
59  
60      /**
61       * List of pending deletions.
62       */
63      private final List<T> pendingDeletions;
64  
65      /**
66       * Count of elements skipped.
67       */
68      private int skipped;
69  
70      /** Handler to call when synchronized sequences are found. */
71      private final ReplacementsHandler<T> handler;
72  
73      /**
74       * Constructs a new instance of {@link ReplacementsFinder}.
75       *
76       * @param handler  handler to call when synchronized sequences are found
77       */
78      public ReplacementsFinder(final ReplacementsHandler<T> handler) {
79          pendingInsertions = new ArrayList<>();
80          pendingDeletions  = new ArrayList<>();
81          skipped           = 0;
82          this.handler      = handler;
83      }
84  
85      /**
86       * Add an object to the pending deletions set.
87       *
88       * @param object  object to delete
89       */
90      @Override
91      public void visitDeleteCommand(final T object) {
92          pendingDeletions.add(object);
93      }
94  
95      /**
96       * Add an object to the pending insertions set.
97       *
98       * @param object  object to insert
99       */
100     @Override
101     public void visitInsertCommand(final T object) {
102         pendingInsertions.add(object);
103     }
104 
105     /**
106      * Handle a synchronization object.
107      * <p>
108      * When a synchronization object is identified, the pending insertions and
109      * pending deletions sets are provided to the user handler as subsequences.
110      * </p>
111      *
112      * @param object  synchronization object detected
113      */
114     @Override
115     public void visitKeepCommand(final T object) {
116         if (pendingDeletions.isEmpty() && pendingInsertions.isEmpty()) {
117             ++skipped;
118         } else {
119             handler.handleReplacement(skipped, pendingDeletions, pendingInsertions);
120             pendingDeletions.clear();
121             pendingInsertions.clear();
122             skipped = 1;
123         }
124     }
125 
126 }