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.html#IntList">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<MergeChunk>() {
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 }