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