1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.lib;
12
13 import java.util.Arrays;
14 import java.util.Iterator;
15 import java.util.NoSuchElementException;
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 public class ObjectIdOwnerMap<V extends ObjectIdOwnerMap.Entry>
41 implements Iterable<V>, ObjectIdSet {
42
43 private static final int INITIAL_DIRECTORY = 1024;
44
45
46 private static final int SEGMENT_BITS = 11;
47
48 private static final int SEGMENT_SHIFT = 32 - SEGMENT_BITS;
49
50
51
52
53
54
55
56 V[][] directory;
57
58
59 int size;
60
61
62 private int grow;
63
64
65 int bits;
66
67
68 private int mask;
69
70
71
72
73 @SuppressWarnings("unchecked")
74 public ObjectIdOwnerMap() {
75 bits = 0;
76 mask = 0;
77 grow = computeGrowAt(bits);
78
79 directory = (V[][]) new Entry[INITIAL_DIRECTORY][];
80 directory[0] = newSegment();
81 }
82
83
84
85
86 public void clear() {
87 size = 0;
88
89 for (V[] tbl : directory) {
90 if (tbl == null)
91 break;
92 Arrays.fill(tbl, null);
93 }
94 }
95
96
97
98
99
100
101
102
103 @SuppressWarnings("unchecked")
104 public V get(AnyObjectId toFind) {
105 if (toFind == null) {
106 return null;
107 }
108 int h = toFind.w1;
109 V obj = directory[h & mask][h >>> SEGMENT_SHIFT];
110 for (; obj != null; obj = (V) obj.next)
111 if (equals(obj, toFind))
112 return obj;
113 return null;
114 }
115
116
117
118
119
120
121 @Override
122 public boolean contains(AnyObjectId toFind) {
123 return get(toFind) != null;
124 }
125
126
127
128
129
130
131
132
133
134
135
136 public <Q extends V> void add(Q newValue) {
137 if (++size == grow)
138 grow();
139
140 int h = newValue.w1;
141 V[] table = directory[h & mask];
142 h >>>= SEGMENT_SHIFT;
143
144 newValue.next = table[h];
145 table[h] = newValue;
146 }
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166 @SuppressWarnings("unchecked")
167 public <Q extends V> V addIfAbsent(Q newValue) {
168 int h = newValue.w1;
169 V[] table = directory[h & mask];
170 h >>>= SEGMENT_SHIFT;
171
172 for (V obj = table[h]; obj != null; obj = (V) obj.next)
173 if (equals(obj, newValue))
174 return obj;
175
176 newValue.next = table[h];
177 table[h] = newValue;
178
179 if (++size == grow)
180 grow();
181 return newValue;
182 }
183
184
185
186
187
188
189 public int size() {
190 return size;
191 }
192
193
194
195
196
197
198 public boolean isEmpty() {
199 return size == 0;
200 }
201
202
203 @Override
204 public Iterator<V> iterator() {
205 return new Iterator<>() {
206 private int found;
207 private int dirIdx;
208 private int tblIdx;
209 private V next;
210
211 @Override
212 public boolean hasNext() {
213 return found < size;
214 }
215
216 @Override
217 public V next() {
218 if (next != null)
219 return found(next);
220
221 for (;;) {
222 V[] table = directory[dirIdx];
223 if (tblIdx == table.length) {
224 if (++dirIdx >= (1 << bits))
225 throw new NoSuchElementException();
226 table = directory[dirIdx];
227 tblIdx = 0;
228 }
229
230 while (tblIdx < table.length) {
231 V v = table[tblIdx++];
232 if (v != null)
233 return found(v);
234 }
235 }
236 }
237
238 @SuppressWarnings("unchecked")
239 private V found(V v) {
240 found++;
241 next = (V) v.next;
242 return v;
243 }
244
245 @Override
246 public void remove() {
247 throw new UnsupportedOperationException();
248 }
249 };
250 }
251
252 @SuppressWarnings("unchecked")
253 private void grow() {
254 final int oldDirLen = 1 << bits;
255 final int s = 1 << bits;
256
257 bits++;
258 mask = (1 << bits) - 1;
259 grow = computeGrowAt(bits);
260
261
262
263
264
265 final int newDirLen = 1 << bits;
266 if (directory.length < newDirLen) {
267 V[][] newDir = (V[][]) new Entry[newDirLen << 1][];
268 System.arraycopy(directory, 0, newDir, 0, oldDirLen);
269 directory = newDir;
270 }
271
272
273
274
275
276
277 for (int dirIdx = 0; dirIdx < oldDirLen; dirIdx++) {
278 final V[] oldTable = directory[dirIdx];
279 final V[] newTable = newSegment();
280
281 for (int i = 0; i < oldTable.length; i++) {
282 V chain0 = null;
283 V chain1 = null;
284 V next;
285
286 for (V obj = oldTable[i]; obj != null; obj = next) {
287 next = (V) obj.next;
288
289 if ((obj.w1 & s) == 0) {
290 obj.next = chain0;
291 chain0 = obj;
292 } else {
293 obj.next = chain1;
294 chain1 = obj;
295 }
296 }
297
298 oldTable[i] = chain0;
299 newTable[i] = chain1;
300 }
301
302 directory[oldDirLen + dirIdx] = newTable;
303 }
304 }
305
306 @SuppressWarnings("unchecked")
307 private final V[] newSegment() {
308 return (V[]) new Entry[1 << SEGMENT_BITS];
309 }
310
311 private static final int computeGrowAt(int bits) {
312 return 1 << (bits + SEGMENT_BITS);
313 }
314
315 private static final boolean equals(AnyObjectId firstObjectId,
316 AnyObjectId secondObjectId) {
317 return firstObjectId.w2 == secondObjectId.w2
318 && firstObjectId.w3 == secondObjectId.w3
319 && firstObjectId.w4 == secondObjectId.w4
320 && firstObjectId.w5 == secondObjectId.w5
321 && firstObjectId.w1 == secondObjectId.w1;
322 }
323
324
325 public abstract static class Entry extends ObjectId {
326 transient Entry next;
327
328
329
330
331
332
333
334 public Entry(AnyObjectId id) {
335 super(id);
336 }
337 }
338 }