Mercurial > hg4j
comparison src/org/tmatesoft/hg/internal/diff/RangePairSeq.java @ 703:7839ff0bfd78
Refactor: move diff/blame related code to a separate package
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 14 Aug 2013 14:51:51 +0200 |
parents | src/org/tmatesoft/hg/internal/RangePairSeq.java@cce0387c6041 |
children |
comparison
equal
deleted
inserted
replaced
702:992fa84e7885 | 703:7839ff0bfd78 |
---|---|
1 /* | |
2 * Copyright (c) 2013 TMate Software Ltd | |
3 * | |
4 * This program is free software; you can redistribute it and/or modify | |
5 * it under the terms of the GNU General Public License as published by | |
6 * the Free Software Foundation; version 2 of the License. | |
7 * | |
8 * This program is distributed in the hope that it will be useful, | |
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 * GNU General Public License for more details. | |
12 * | |
13 * For information on how to redistribute this software under | |
14 * the terms of a license other than GNU General Public License | |
15 * contact TMate Software at support@hg4j.com | |
16 */ | |
17 package org.tmatesoft.hg.internal.diff; | |
18 | |
19 import java.util.Formatter; | |
20 | |
21 import org.tmatesoft.hg.internal.IntSliceSeq; | |
22 import org.tmatesoft.hg.internal.IntTuple; | |
23 | |
24 /** | |
25 * Sequence of range pairs (denoted origin and target), {originStart, targetStart, length}, tailored for diff/annotate | |
26 * | |
27 * @author Artem Tikhomirov | |
28 * @author TMate Software Ltd. | |
29 */ | |
30 public final class RangePairSeq { | |
31 private final IntSliceSeq ranges = new IntSliceSeq(3); | |
32 | |
33 public void add(int start1, int start2, int length) { | |
34 int count = ranges.size(); | |
35 if (count > 0) { | |
36 int lastS1 = ranges.get(--count, 0); | |
37 int lastS2 = ranges.get(count, 1); | |
38 int lastLen = ranges.get(count, 2); | |
39 if (start1 == lastS1 + lastLen && start2 == lastS2 + lastLen) { | |
40 // new range continues the previous one - just increase the length | |
41 ranges.set(count, lastS1, lastS2, lastLen + length); | |
42 return; | |
43 } | |
44 } | |
45 ranges.add(start1, start2, length); | |
46 } | |
47 | |
48 public void clear() { | |
49 ranges.clear(); | |
50 } | |
51 | |
52 public int size() { | |
53 return ranges.size(); | |
54 } | |
55 | |
56 /** | |
57 * find out line index in the target that matches specified origin line | |
58 */ | |
59 public int mapLineIndex(int ln) { | |
60 for (IntTuple t : ranges) { | |
61 int s1 = t.at(0); | |
62 if (s1 > ln) { | |
63 return -1; | |
64 } | |
65 int l = t.at(2); | |
66 if (s1 + l > ln) { | |
67 int s2 = t.at(1); | |
68 return s2 + (ln - s1); | |
69 } | |
70 } | |
71 return -1; | |
72 } | |
73 | |
74 /** | |
75 * find out line index in origin that matches specified target line | |
76 */ | |
77 public int reverseMapLine(int targetLine) { | |
78 for (IntTuple t : ranges) { | |
79 int ts = t.at(1); | |
80 if (ts > targetLine) { | |
81 return -1; | |
82 } | |
83 int l = t.at(2); | |
84 if (ts + l > targetLine) { | |
85 int os = t.at(0); | |
86 return os + (targetLine - ts); | |
87 } | |
88 } | |
89 return -1; | |
90 } | |
91 | |
92 public RangePairSeq intersect(RangePairSeq target) { | |
93 RangePairSeq v = new RangePairSeq(); | |
94 for (IntTuple t : ranges) { | |
95 int originLine = t.at(0); | |
96 int targetLine = t.at(1); | |
97 int length = t.at(2); | |
98 int startTargetLine = -1, startOriginLine = -1, c = 0; | |
99 for (int j = 0; j < length; j++) { | |
100 int lnInFinal = target.mapLineIndex(targetLine + j); | |
101 if (lnInFinal == -1 || (startTargetLine != -1 && lnInFinal != startTargetLine + c)) { | |
102 // the line is not among "same" in ultimate origin | |
103 // or belongs to another/next "same" chunk | |
104 if (startOriginLine == -1) { | |
105 continue; | |
106 } | |
107 v.add(startOriginLine, startTargetLine, c); | |
108 c = 0; | |
109 startOriginLine = startTargetLine = -1; | |
110 // fall-through to check if it's not complete miss but a next chunk | |
111 } | |
112 if (lnInFinal != -1) { | |
113 if (startOriginLine == -1) { | |
114 startOriginLine = originLine + j; | |
115 startTargetLine = lnInFinal; | |
116 c = 1; | |
117 } else { | |
118 // lnInFinal != startTargetLine + s is covered above | |
119 assert lnInFinal == startTargetLine + c; | |
120 c++; | |
121 } | |
122 } | |
123 } | |
124 if (startOriginLine != -1) { | |
125 assert c > 0; | |
126 v.add(startOriginLine, startTargetLine, c); | |
127 } | |
128 } | |
129 return v; | |
130 } | |
131 | |
132 // true when specified line in origin is equal to a line in target | |
133 public boolean includesOriginLine(int ln) { | |
134 return includes(ln, 0); | |
135 } | |
136 | |
137 // true when specified line in target is equal to a line in origin | |
138 public boolean includesTargetLine(int ln) { | |
139 return includes(ln, 1); | |
140 } | |
141 | |
142 private boolean includes(int ln, int o) { | |
143 for (IntTuple t : ranges) { | |
144 int rangeStart = t.at(o); | |
145 if (rangeStart > ln) { | |
146 return false; | |
147 } | |
148 int rangeLen = t.at(2); | |
149 if (rangeStart + rangeLen > ln) { | |
150 return true; | |
151 } | |
152 } | |
153 return false; | |
154 } | |
155 | |
156 public CharSequence dump() { | |
157 StringBuilder sb = new StringBuilder(); | |
158 Formatter f = new Formatter(sb); | |
159 for (IntTuple t : ranges) { | |
160 int s1 = t.at(0); | |
161 int s2 = t.at(1); | |
162 int len = t.at(2); | |
163 f.format("[%d..%d) == [%d..%d); ", s1, s1 + len, s2, s2 + len); | |
164 } | |
165 return sb; | |
166 } | |
167 | |
168 @Override | |
169 public String toString() { | |
170 return String.format("RangeSeq[%d]:%s", size(), dump()); | |
171 } | |
172 } |