1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package org.eclipse.jgit.diff;
46
47 import static org.eclipse.jgit.util.RawCharUtil.isWhitespace;
48 import static org.eclipse.jgit.util.RawCharUtil.trimLeadingWhitespace;
49 import static org.eclipse.jgit.util.RawCharUtil.trimTrailingWhitespace;
50
51 import org.eclipse.jgit.util.IntList;
52
53
54 public abstract class RawTextComparator extends SequenceComparator<RawText> {
55
56 public static final RawTextComparator DEFAULT = new RawTextComparator() {
57 @Override
58 public boolean equals(RawText a, int ai, RawText b, int bi) {
59 ai++;
60 bi++;
61
62 int as = a.lines.get(ai);
63 int bs = b.lines.get(bi);
64 final int ae = a.lines.get(ai + 1);
65 final int be = b.lines.get(bi + 1);
66
67 if (ae - as != be - bs)
68 return false;
69
70 while (as < ae) {
71 if (a.content[as++] != b.content[bs++])
72 return false;
73 }
74 return true;
75 }
76
77 @Override
78 protected int hashRegion(final byte[] raw, int ptr, final int end) {
79 int hash = 5381;
80 for (; ptr < end; ptr++)
81 hash = ((hash << 5) + hash) + (raw[ptr] & 0xff);
82 return hash;
83 }
84 };
85
86
87 public static final RawTextComparator WS_IGNORE_ALL = new RawTextComparator() {
88 @Override
89 public boolean equals(RawText a, int ai, RawText b, int bi) {
90 ai++;
91 bi++;
92
93 int as = a.lines.get(ai);
94 int bs = b.lines.get(bi);
95 int ae = a.lines.get(ai + 1);
96 int be = b.lines.get(bi + 1);
97
98 ae = trimTrailingWhitespace(a.content, as, ae);
99 be = trimTrailingWhitespace(b.content, bs, be);
100
101 while (as < ae && bs < be) {
102 byte ac = a.content[as];
103 byte bc = b.content[bs];
104
105 while (as < ae - 1 && isWhitespace(ac)) {
106 as++;
107 ac = a.content[as];
108 }
109
110 while (bs < be - 1 && isWhitespace(bc)) {
111 bs++;
112 bc = b.content[bs];
113 }
114
115 if (ac != bc)
116 return false;
117
118 as++;
119 bs++;
120 }
121
122 return as == ae && bs == be;
123 }
124
125 @Override
126 protected int hashRegion(byte[] raw, int ptr, int end) {
127 int hash = 5381;
128 for (; ptr < end; ptr++) {
129 byte c = raw[ptr];
130 if (!isWhitespace(c))
131 hash = ((hash << 5) + hash) + (c & 0xff);
132 }
133 return hash;
134 }
135 };
136
137
138 public static final RawTextComparator WS_IGNORE_LEADING = new RawTextComparator() {
139 @Override
140 public boolean equals(RawText a, int ai, RawText b, int bi) {
141 ai++;
142 bi++;
143
144 int as = a.lines.get(ai);
145 int bs = b.lines.get(bi);
146 int ae = a.lines.get(ai + 1);
147 int be = b.lines.get(bi + 1);
148
149 as = trimLeadingWhitespace(a.content, as, ae);
150 bs = trimLeadingWhitespace(b.content, bs, be);
151
152 if (ae - as != be - bs)
153 return false;
154
155 while (as < ae) {
156 if (a.content[as++] != b.content[bs++])
157 return false;
158 }
159 return true;
160 }
161
162 @Override
163 protected int hashRegion(final byte[] raw, int ptr, int end) {
164 int hash = 5381;
165 ptr = trimLeadingWhitespace(raw, ptr, end);
166 for (; ptr < end; ptr++)
167 hash = ((hash << 5) + hash) + (raw[ptr] & 0xff);
168 return hash;
169 }
170 };
171
172
173 public static final RawTextComparator WS_IGNORE_TRAILING = new RawTextComparator() {
174 @Override
175 public boolean equals(RawText a, int ai, RawText b, int bi) {
176 ai++;
177 bi++;
178
179 int as = a.lines.get(ai);
180 int bs = b.lines.get(bi);
181 int ae = a.lines.get(ai + 1);
182 int be = b.lines.get(bi + 1);
183
184 ae = trimTrailingWhitespace(a.content, as, ae);
185 be = trimTrailingWhitespace(b.content, bs, be);
186
187 if (ae - as != be - bs)
188 return false;
189
190 while (as < ae) {
191 if (a.content[as++] != b.content[bs++])
192 return false;
193 }
194 return true;
195 }
196
197 @Override
198 protected int hashRegion(final byte[] raw, int ptr, int end) {
199 int hash = 5381;
200 end = trimTrailingWhitespace(raw, ptr, end);
201 for (; ptr < end; ptr++)
202 hash = ((hash << 5) + hash) + (raw[ptr] & 0xff);
203 return hash;
204 }
205 };
206
207
208 public static final RawTextComparator WS_IGNORE_CHANGE = new RawTextComparator() {
209 @Override
210 public boolean equals(RawText a, int ai, RawText b, int bi) {
211 ai++;
212 bi++;
213
214 int as = a.lines.get(ai);
215 int bs = b.lines.get(bi);
216 int ae = a.lines.get(ai + 1);
217 int be = b.lines.get(bi + 1);
218
219 ae = trimTrailingWhitespace(a.content, as, ae);
220 be = trimTrailingWhitespace(b.content, bs, be);
221
222 while (as < ae && bs < be) {
223 byte ac = a.content[as];
224 byte bc = b.content[bs];
225
226 if (ac != bc)
227 return false;
228
229 if (isWhitespace(ac))
230 as = trimLeadingWhitespace(a.content, as, ae);
231 else
232 as++;
233
234 if (isWhitespace(bc))
235 bs = trimLeadingWhitespace(b.content, bs, be);
236 else
237 bs++;
238 }
239 return as == ae && bs == be;
240 }
241
242 @Override
243 protected int hashRegion(final byte[] raw, int ptr, int end) {
244 int hash = 5381;
245 end = trimTrailingWhitespace(raw, ptr, end);
246 while (ptr < end) {
247 byte c = raw[ptr];
248 hash = ((hash << 5) + hash) + (c & 0xff);
249 if (isWhitespace(c))
250 ptr = trimLeadingWhitespace(raw, ptr, end);
251 else
252 ptr++;
253 }
254 return hash;
255 }
256 };
257
258 @Override
259 public int hash(RawText seq, int lno) {
260 final int begin = seq.lines.get(lno + 1);
261 final int end = seq.lines.get(lno + 2);
262 return hashRegion(seq.content, begin, end);
263 }
264
265 @Override
266 public Edit reduceCommonStartEnd(RawText a, RawText b, Edit e) {
267
268
269
270
271
272
273 if (e.beginA == e.endA || e.beginB == e.endB)
274 return e;
275
276 byte[] aRaw = a.content;
277 byte[] bRaw = b.content;
278
279 int aPtr = a.lines.get(e.beginA + 1);
280 int bPtr = a.lines.get(e.beginB + 1);
281
282 int aEnd = a.lines.get(e.endA + 1);
283 int bEnd = b.lines.get(e.endB + 1);
284
285
286
287
288
289 if (aPtr < 0 || bPtr < 0 || aEnd > aRaw.length || bEnd > bRaw.length)
290 throw new ArrayIndexOutOfBoundsException();
291
292 while (aPtr < aEnd && bPtr < bEnd && aRaw[aPtr] == bRaw[bPtr]) {
293 aPtr++;
294 bPtr++;
295 }
296
297 while (aPtr < aEnd && bPtr < bEnd && aRaw[aEnd - 1] == bRaw[bEnd - 1]) {
298 aEnd--;
299 bEnd--;
300 }
301
302 e.beginA = findForwardLine(a.lines, e.beginA, aPtr);
303 e.beginB = findForwardLine(b.lines, e.beginB, bPtr);
304
305 e.endA = findReverseLine(a.lines, e.endA, aEnd);
306
307 final boolean partialA = aEnd < a.lines.get(e.endA + 1);
308 if (partialA)
309 bEnd += a.lines.get(e.endA + 1) - aEnd;
310
311 e.endB = findReverseLine(b.lines, e.endB, bEnd);
312
313 if (!partialA && bEnd < b.lines.get(e.endB + 1))
314 e.endA++;
315
316 return super.reduceCommonStartEnd(a, b, e);
317 }
318
319 private static int findForwardLine(IntList lines, int idx, int ptr) {
320 final int end = lines.size() - 2;
321 while (idx < end && lines.get(idx + 2) < ptr)
322 idx++;
323 return idx;
324 }
325
326 private static int findReverseLine(IntList lines, int idx, int ptr) {
327 while (0 < idx && ptr <= lines.get(idx))
328 idx--;
329 return idx;
330 }
331
332
333
334
335
336
337
338
339
340
341
342
343 protected abstract int hashRegion(byte[] raw, int ptr, int end);
344 }