1 /* 2 * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com> and others 3 * 4 * This program and the accompanying materials are made available under the 5 * terms of the Eclipse Distribution License v. 1.0 which is available at 6 * https://www.eclipse.org/org/documents/edl-v10.php. 7 * 8 * SPDX-License-Identifier: BSD-3-Clause 9 */ 10 11 package org.eclipse.jgit.merge; 12 13 import java.util.Iterator; 14 import java.util.List; 15 16 import org.eclipse.jgit.diff.Sequence; 17 import org.eclipse.jgit.merge.MergeChunk.ConflictState; 18 import org.eclipse.jgit.util.IntList; 19 20 /** 21 * The result of merging a number of {@link org.eclipse.jgit.diff.Sequence} 22 * objects. These sequences have one common predecessor sequence. The result of 23 * a merge is a list of MergeChunks. Each MergeChunk contains either a range (a 24 * subsequence) from one of the merged sequences, a range from the common 25 * predecessor or a conflicting range from one of the merged sequences. A 26 * conflict will be reported as multiple chunks, one for each conflicting range. 27 * The first chunk for a conflict is marked specially to distinguish the border 28 * between two consecutive conflicts. 29 * <p> 30 * This class does not know anything about how to present the merge result to 31 * the end-user. MergeFormatters have to be used to construct something human 32 * readable. 33 * 34 * @param <S> 35 * type of sequence. 36 */ 37 public class MergeResult<S extends Sequence> implements Iterable<MergeChunk> { 38 private final List<S> sequences; 39 40 final IntList chunks = new IntList(); 41 42 private boolean containsConflicts = false; 43 44 /** 45 * Creates a new empty MergeResult 46 * 47 * @param sequences 48 * contains the common predecessor sequence at position 0 49 * followed by the merged sequences. This list should not be 50 * modified anymore during the lifetime of this 51 * {@link org.eclipse.jgit.merge.MergeResult}. 52 */ 53 public MergeResult(List<S> sequences) { 54 this.sequences = sequences; 55 } 56 57 /** 58 * Adds a new range from one of the merged sequences or from the common 59 * predecessor. This method can add conflicting and non-conflicting ranges 60 * controlled by the conflictState parameter 61 * 62 * @param srcIdx 63 * determines from which sequence this range comes. An index of 64 * x specifies the x+1 element in the list of sequences 65 * specified to the constructor 66 * @param begin 67 * the first element from the specified sequence which should be 68 * included in the merge result. Indexes start with 0. 69 * @param end 70 * specifies the end of the range to be added. The element this 71 * index points to is the first element which not added to the 72 * merge result. All elements between begin (including begin) and 73 * this element are added. 74 * @param conflictState 75 * when set to NO_CONLICT a non-conflicting range is added. 76 * This will end implicitly all open conflicts added before. 77 */ 78 public void add(int srcIdx, int begin, int end, ConflictState conflictState) { 79 chunks.add(conflictState.ordinal()); 80 chunks.add(srcIdx); 81 chunks.add(begin); 82 chunks.add(end); 83 if (conflictState != ConflictState.NO_CONFLICT) 84 containsConflicts = true; 85 } 86 87 /** 88 * Returns the common predecessor sequence and the merged sequence in one 89 * list. The common predecessor is the first element in the list 90 * 91 * @return the common predecessor at position 0 followed by the merged 92 * sequences. 93 */ 94 public List<S> getSequences() { 95 return sequences; 96 } 97 98 static final ConflictState[] states = ConflictState.values(); 99 100 /** {@inheritDoc} */ 101 @Override 102 public Iterator<MergeChunk> iterator() { 103 return new Iterator<>() { 104 int idx; 105 106 @Override 107 public boolean hasNext() { 108 return (idx < chunks.size()); 109 } 110 111 @Override 112 public MergeChunk next() { 113 ConflictState state = states[chunks.get(idx++)]; 114 int srcIdx = chunks.get(idx++); 115 int begin = chunks.get(idx++); 116 int end = chunks.get(idx++); 117 return new MergeChunk(srcIdx, begin, end, state); 118 } 119 120 @Override 121 public void remove() { 122 throw new UnsupportedOperationException(); 123 } 124 }; 125 } 126 127 /** 128 * Whether this merge result contains conflicts 129 * 130 * @return true if this merge result contains conflicts 131 */ 132 public boolean containsConflicts() { 133 return containsConflicts; 134 } 135 136 /** 137 * Sets explicitly whether this merge should be seen as containing a 138 * conflict or not. Needed because during RecursiveMerger we want to do 139 * content-merges and take the resulting content (even with conflict 140 * markers!) as new conflict-free content 141 * 142 * @param containsConflicts 143 * whether this merge should be seen as containing a conflict or 144 * not. 145 * @since 3.5 146 */ 147 protected void setContainsConflicts(boolean containsConflicts) { 148 this.containsConflicts = containsConflicts; 149 } 150 }