1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.util;
12
13 import java.util.AbstractMap;
14 import java.util.AbstractSet;
15 import java.util.Iterator;
16 import java.util.Map;
17 import java.util.NoSuchElementException;
18 import java.util.Set;
19 import java.util.function.BinaryOperator;
20 import java.util.stream.Collector;
21 import java.util.stream.Collectors;
22
23 import org.eclipse.jgit.lib.AnyObjectId;
24 import org.eclipse.jgit.lib.ObjectId;
25 import org.eclipse.jgit.lib.Ref;
26 import org.eclipse.jgit.lib.RefComparator;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public class RefMap extends AbstractMap<String, Ref> {
47
48
49
50
51
52
53 final String prefix;
54
55
56 RefList<Ref> packed;
57
58
59
60
61
62
63
64
65
66 RefList<Ref> loose;
67
68
69
70
71
72
73
74
75
76 RefList<Ref> resolved;
77
78 int size;
79
80 boolean sizeIsValid;
81
82 private Set<Entry<String, Ref>> entrySet;
83
84
85
86
87 public RefMap() {
88 prefix = "";
89 packed = RefList.emptyList();
90 loose = RefList.emptyList();
91 resolved = RefList.emptyList();
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 @SuppressWarnings("unchecked")
114 public RefMap(String prefix, RefList<? extends Ref> packed,
115 RefList<? extends Ref> loose, RefList<? extends Ref> resolved) {
116 this.prefix = prefix;
117 this.packed = (RefList<Ref>) packed;
118 this.loose = (RefList<Ref>) loose;
119 this.resolved = (RefList<Ref>) resolved;
120 }
121
122
123 @Override
124 public boolean containsKey(Object name) {
125 return get(name) != null;
126 }
127
128
129 @Override
130 public Ref get(Object key) {
131 String name = toRefName((String) key);
132 Ref ref = resolved.get(name);
133 if (ref == null)
134 ref = loose.get(name);
135 if (ref == null)
136 ref = packed.get(name);
137 return ref;
138 }
139
140
141 @Override
142 public Ref put(String keyName, Ref value) {
143 String name = toRefName(keyName);
144
145 if (!name.equals(value.getName()))
146 throw new IllegalArgumentException();
147
148 if (!resolved.isEmpty()) {
149
150
151 for (Ref ref : resolved)
152 loose = loose.put(ref);
153 resolved = RefList.emptyList();
154 }
155
156 int idx = loose.find(name);
157 if (0 <= idx) {
158 Ref prior = loose.get(name);
159 loose = loose.set(idx, value);
160 return prior;
161 }
162 Ref prior = get(keyName);
163 loose = loose.add(idx, value);
164 sizeIsValid = false;
165 return prior;
166 }
167
168
169 @Override
170 public Ref remove(Object key) {
171 String name = toRefName((String) key);
172 Ref res = null;
173 int idx;
174 if (0 <= (idx = packed.find(name))) {
175 res = packed.get(name);
176 packed = packed.remove(idx);
177 sizeIsValid = false;
178 }
179 if (0 <= (idx = loose.find(name))) {
180 res = loose.get(name);
181 loose = loose.remove(idx);
182 sizeIsValid = false;
183 }
184 if (0 <= (idx = resolved.find(name))) {
185 res = resolved.get(name);
186 resolved = resolved.remove(idx);
187 sizeIsValid = false;
188 }
189 return res;
190 }
191
192
193 @Override
194 public boolean isEmpty() {
195 return entrySet().isEmpty();
196 }
197
198
199 @Override
200 public Set<Entry<String, Ref>> entrySet() {
201 if (entrySet == null) {
202 entrySet = new AbstractSet<>() {
203
204 @Override
205 public Iterator<Entry<String, Ref>> iterator() {
206 return new SetIterator();
207 }
208
209 @Override
210 public int size() {
211 if (!sizeIsValid) {
212 size = 0;
213 Iterator<?> i = entrySet().iterator();
214 for (; i.hasNext(); i.next())
215 size++;
216 sizeIsValid = true;
217 }
218 return size;
219 }
220
221 @Override
222 public boolean isEmpty() {
223 if (sizeIsValid)
224 return 0 == size;
225 return !iterator().hasNext();
226 }
227
228 @Override
229 public void clear() {
230 packed = RefList.emptyList();
231 loose = RefList.emptyList();
232 resolved = RefList.emptyList();
233 size = 0;
234 sizeIsValid = true;
235 }
236 };
237 }
238 return entrySet;
239 }
240
241
242 @Override
243 public String toString() {
244 StringBuilder r = new StringBuilder();
245 boolean first = true;
246 r.append('[');
247 for (Ref ref : values()) {
248 if (first)
249 first = false;
250 else
251 r.append(", ");
252 r.append(ref);
253 }
254 r.append(']');
255 return r.toString();
256 }
257
258
259
260
261
262
263
264
265 public static Collector<Ref, ?, RefMap> toRefMap(
266 BinaryOperator<Ref> mergeFunction) {
267 return Collectors.collectingAndThen(RefList.toRefList(mergeFunction),
268 (refs) -> new RefMap("",
269 refs, RefList.emptyList(),
270 RefList.emptyList()));
271 }
272
273 private String toRefName(String name) {
274 if (0 < prefix.length())
275 name = prefix + name;
276 return name;
277 }
278
279 String toMapKey(Ref ref) {
280 String name = ref.getName();
281 if (0 < prefix.length())
282 name = name.substring(prefix.length());
283 return name;
284 }
285
286 private class SetIterator implements Iterator<Entry<String, Ref>> {
287 private int packedIdx;
288
289 private int looseIdx;
290
291 private int resolvedIdx;
292
293 private Entry<String, Ref> next;
294
295 SetIterator() {
296 if (0 < prefix.length()) {
297 packedIdx = -(packed.find(prefix) + 1);
298 looseIdx = -(loose.find(prefix) + 1);
299 resolvedIdx = -(resolved.find(prefix) + 1);
300 }
301 }
302
303 @Override
304 public boolean hasNext() {
305 if (next == null)
306 next = peek();
307 return next != null;
308 }
309
310 @Override
311 public Entry<String, Ref> next() {
312 if (hasNext()) {
313 Entry<String, Ref> r = next;
314 next = peek();
315 return r;
316 }
317 throw new NoSuchElementException();
318 }
319
320 public Entry<String, Ref> peek() {
321 if (packedIdx < packed.size() && looseIdx < loose.size()) {
322 Ref p = packed.get(packedIdx);
323 Ref l = loose.get(looseIdx);
324 int cmp = RefComparator.compareTo(p, l);
325 if (cmp < 0) {
326 packedIdx++;
327 return toEntry(p);
328 }
329
330 if (cmp == 0)
331 packedIdx++;
332 looseIdx++;
333 return toEntry(resolveLoose(l));
334 }
335
336 if (looseIdx < loose.size())
337 return toEntry(resolveLoose(loose.get(looseIdx++)));
338 if (packedIdx < packed.size())
339 return toEntry(packed.get(packedIdx++));
340 return null;
341 }
342
343 private Ref resolveLoose(Ref l) {
344 if (resolvedIdx < resolved.size()) {
345 Ref r = resolved.get(resolvedIdx);
346 int cmp = RefComparator.compareTo(l, r);
347 if (cmp == 0) {
348 resolvedIdx++;
349 return r;
350 } else if (cmp > 0) {
351
352
353 throw new IllegalStateException();
354 }
355 }
356 return l;
357 }
358
359 private Ent toEntry(Ref p) {
360 if (p.getName().startsWith(prefix))
361 return new Ent(p);
362 packedIdx = packed.size();
363 looseIdx = loose.size();
364 resolvedIdx = resolved.size();
365 return null;
366 }
367
368 @Override
369 public void remove() {
370 throw new UnsupportedOperationException();
371 }
372 }
373
374 private class Ent implements Entry<String, Ref> {
375 private Ref ref;
376
377 Ent(Ref ref) {
378 this.ref = ref;
379 }
380
381 @Override
382 public String getKey() {
383 return toMapKey(ref);
384 }
385
386 @Override
387 public Ref getValue() {
388 return ref;
389 }
390
391 @Override
392 public Ref setValue(Ref value) {
393 Ref prior = put(getKey(), value);
394 ref = value;
395 return prior;
396 }
397
398 @Override
399 public int hashCode() {
400 return getKey().hashCode();
401 }
402
403 @Override
404 public boolean equals(Object obj) {
405 if (obj instanceof Map.Entry) {
406 final Object key = ((Map.Entry) obj).getKey();
407 final Object val = ((Map.Entry) obj).getValue();
408 if (key instanceof String && val instanceof Ref) {
409 final Ref r = (Ref) val;
410 if (r.getName().equals(ref.getName())) {
411 final ObjectId a = r.getObjectId();
412 final ObjectId b = ref.getObjectId();
413 if (a != null && b != null
414 && AnyObjectId.isEqual(a, b)) {
415 return true;
416 }
417 }
418 }
419 }
420 return false;
421 }
422
423 @Override
424 public String toString() {
425 return ref.toString();
426 }
427 }
428 }