ReplacementsFinder.java

  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. import java.util.ArrayList;
  19. import java.util.List;

  20. /**
  21.  * This class handles sequences of replacements resulting from a comparison.
  22.  * <p>
  23.  * The comparison of two objects sequences leads to the identification of common
  24.  * parts and parts which only belong to the first or to the second sequence. The
  25.  * common parts appear in the edit script in the form of <em>keep</em> commands,
  26.  * they can be considered as synchronization objects between the two sequences.
  27.  * These synchronization objects split the two sequences in synchronized
  28.  * sub-sequences. The first sequence can be transformed into the second one by
  29.  * replacing each synchronized sub-sequence of the first sequence by the
  30.  * corresponding sub-sequence of the second sequence. This is a synthetic way to
  31.  * see an {@link EditScript edit script}, replacing individual
  32.  * {@link DeleteCommand delete}, {@link KeepCommand keep} and
  33.  * {@link InsertCommand insert} commands by fewer replacements acting on
  34.  * complete sub-sequences.
  35.  * </p>
  36.  * <p>
  37.  * This class is devoted to perform this interpretation. It visits an
  38.  * {@link EditScript edit script} (because it implements the
  39.  * {@link CommandVisitor CommandVisitor} interface) and calls a user-supplied
  40.  * handler implementing the {@link ReplacementsHandler ReplacementsHandler}
  41.  * interface to process the sub-sequences.
  42.  * </p>
  43.  *
  44.  * @see ReplacementsHandler
  45.  * @see EditScript
  46.  * @see StringsComparator
  47.  * @param <T> object type
  48.  * @since 1.0
  49.  */
  50. public class ReplacementsFinder<T> implements CommandVisitor<T> {

  51.     /**
  52.      * List of pending insertions.
  53.      */
  54.     private final List<T> pendingInsertions;

  55.     /**
  56.      * List of pending deletions.
  57.      */
  58.     private final List<T> pendingDeletions;

  59.     /**
  60.      * Count of elements skipped.
  61.      */
  62.     private int skipped;

  63.     /** Handler to call when synchronized sequences are found. */
  64.     private final ReplacementsHandler<T> handler;

  65.     /**
  66.      * Constructs a new instance of {@link ReplacementsFinder}.
  67.      *
  68.      * @param handler  handler to call when synchronized sequences are found
  69.      */
  70.     public ReplacementsFinder(final ReplacementsHandler<T> handler) {
  71.         pendingInsertions = new ArrayList<>();
  72.         pendingDeletions  = new ArrayList<>();
  73.         skipped           = 0;
  74.         this.handler      = handler;
  75.     }

  76.     /**
  77.      * Add an object to the pending deletions set.
  78.      *
  79.      * @param object  object to delete
  80.      */
  81.     @Override
  82.     public void visitDeleteCommand(final T object) {
  83.         pendingDeletions.add(object);
  84.     }

  85.     /**
  86.      * Add an object to the pending insertions set.
  87.      *
  88.      * @param object  object to insert
  89.      */
  90.     @Override
  91.     public void visitInsertCommand(final T object) {
  92.         pendingInsertions.add(object);
  93.     }

  94.     /**
  95.      * Handle a synchronization object.
  96.      * <p>
  97.      * When a synchronization object is identified, the pending insertions and
  98.      * pending deletions sets are provided to the user handler as subsequences.
  99.      * </p>
  100.      *
  101.      * @param object  synchronization object detected
  102.      */
  103.     @Override
  104.     public void visitKeepCommand(final T object) {
  105.         if (pendingDeletions.isEmpty() && pendingInsertions.isEmpty()) {
  106.             ++skipped;
  107.         } else {
  108.             handler.handleReplacement(skipped, pendingDeletions, pendingInsertions);
  109.             pendingDeletions.clear();
  110.             pendingInsertions.clear();
  111.             skipped = 1;
  112.         }
  113.     }

  114. }