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.AbstractList;
47 import java.util.Arrays;
48 import java.util.Iterator;
49 import java.util.NoSuchElementException;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public class BlockList<T> extends AbstractList<T> {
71 private static final int BLOCK_BITS = 10;
72
73 static final int BLOCK_SIZE = 1 << BLOCK_BITS;
74
75 private static final int BLOCK_MASK = BLOCK_SIZE - 1;
76
77 T[][] directory;
78
79 int size;
80
81 private int tailDirIdx;
82
83 private int tailBlkIdx;
84
85 private T[] tailBlock;
86
87
88
89
90 public BlockList() {
91 directory = BlockList.<T> newDirectory(256);
92 directory[0] = BlockList.<T> newBlock();
93 tailBlock = directory[0];
94 }
95
96
97
98
99
100
101
102 public BlockList(int capacity) {
103 int dirSize = toDirectoryIndex(capacity);
104 if ((capacity & BLOCK_MASK) != 0 || dirSize == 0)
105 dirSize++;
106 directory = BlockList.<T> newDirectory(dirSize);
107 directory[0] = BlockList.<T> newBlock();
108 tailBlock = directory[0];
109 }
110
111
112 @Override
113 public int size() {
114 return size;
115 }
116
117
118 @Override
119 public void clear() {
120 for (T[] block : directory) {
121 if (block != null)
122 Arrays.fill(block, null);
123 }
124 size = 0;
125 tailDirIdx = 0;
126 tailBlkIdx = 0;
127 tailBlock = directory[0];
128 }
129
130
131 @Override
132 public T get(int index) {
133 if (index < 0 || size <= index)
134 throw new IndexOutOfBoundsException(String.valueOf(index));
135 return directory[toDirectoryIndex(index)][toBlockIndex(index)];
136 }
137
138
139 @Override
140 public T set(int index, T element) {
141 if (index < 0 || size <= index)
142 throw new IndexOutOfBoundsException(String.valueOf(index));
143 T[] blockRef = directory[toDirectoryIndex(index)];
144 int blockIdx = toBlockIndex(index);
145 T old = blockRef[blockIdx];
146 blockRef[blockIdx] = element;
147 return old;
148 }
149
150
151
152
153
154
155
156 public void addAll(BlockList<T> src) {
157 if (src.size == 0)
158 return;
159
160 int srcDirIdx = 0;
161 for (; srcDirIdx < src.tailDirIdx; srcDirIdx++)
162 addAll(src.directory[srcDirIdx], 0, BLOCK_SIZE);
163 if (src.tailBlkIdx != 0)
164 addAll(src.tailBlock, 0, src.tailBlkIdx);
165 }
166
167
168
169
170
171
172
173
174
175
176
177 public void addAll(T[] src, int srcIdx, int srcCnt) {
178 while (0 < srcCnt) {
179 int i = tailBlkIdx;
180 int n = Math.min(srcCnt, BLOCK_SIZE - i);
181 if (n == 0) {
182
183 add(src[srcIdx++]);
184 srcCnt--;
185 continue;
186 }
187
188 System.arraycopy(src, srcIdx, tailBlock, i, n);
189 tailBlkIdx += n;
190 size += n;
191 srcIdx += n;
192 srcCnt -= n;
193 }
194 }
195
196
197 @Override
198 public boolean add(T element) {
199 int i = tailBlkIdx;
200 if (i < BLOCK_SIZE) {
201
202 tailBlock[i] = element;
203 tailBlkIdx = i + 1;
204 size++;
205 return true;
206 }
207
208
209 if (++tailDirIdx == directory.length) {
210 T[][] newDir = BlockList.<T> newDirectory(directory.length << 1);
211 System.arraycopy(directory, 0, newDir, 0, directory.length);
212 directory = newDir;
213 }
214
215 T[] blockRef = directory[tailDirIdx];
216 if (blockRef == null) {
217 blockRef = BlockList.<T> newBlock();
218 directory[tailDirIdx] = blockRef;
219 }
220 blockRef[0] = element;
221 tailBlock = blockRef;
222 tailBlkIdx = 1;
223 size++;
224 return true;
225 }
226
227
228 @Override
229 public void add(int index, T element) {
230 if (index == size) {
231
232 add(element);
233
234 } else if (index < 0 || size < index) {
235 throw new IndexOutOfBoundsException(String.valueOf(index));
236
237 } else {
238
239
240
241
242 add(null);
243 for (int oldIdx = size - 2; index <= oldIdx; oldIdx--)
244 set(oldIdx + 1, get(oldIdx));
245 set(index, element);
246 }
247 }
248
249
250 @Override
251 public T remove(int index) {
252 if (index == size - 1) {
253
254 T[] blockRef = directory[toDirectoryIndex(index)];
255 int blockIdx = toBlockIndex(index);
256 T old = blockRef[blockIdx];
257 blockRef[blockIdx] = null;
258 size--;
259 if (0 < tailBlkIdx)
260 tailBlkIdx--;
261 else
262 resetTailBlock();
263 return old;
264
265 } else if (index < 0 || size <= index) {
266 throw new IndexOutOfBoundsException(String.valueOf(index));
267
268 } else {
269
270
271
272
273 T old = get(index);
274 for (; index < size - 1; index++)
275 set(index, get(index + 1));
276 set(size - 1, null);
277 size--;
278 resetTailBlock();
279 return old;
280 }
281 }
282
283 private void resetTailBlock() {
284 tailDirIdx = toDirectoryIndex(size);
285 tailBlkIdx = toBlockIndex(size);
286 tailBlock = directory[tailDirIdx];
287 }
288
289
290 @Override
291 public Iterator<T> iterator() {
292 return new MyIterator();
293 }
294
295 static final int toDirectoryIndex(int index) {
296 return index >>> BLOCK_BITS;
297 }
298
299 static final int toBlockIndex(int index) {
300 return index & BLOCK_MASK;
301 }
302
303 @SuppressWarnings("unchecked")
304 private static <T> T[][] newDirectory(int size) {
305 return (T[][]) new Object[size][];
306 }
307
308 @SuppressWarnings("unchecked")
309 private static <T> T[] newBlock() {
310 return (T[]) new Object[BLOCK_SIZE];
311 }
312
313 private class MyIterator implements Iterator<T> {
314 private int index;
315
316 private int dirIdx;
317
318 private int blkIdx;
319
320 private T[] block = directory[0];
321
322 @Override
323 public boolean hasNext() {
324 return index < size;
325 }
326
327 @Override
328 public T next() {
329 if (size <= index)
330 throw new NoSuchElementException();
331
332 T res = block[blkIdx];
333 if (++blkIdx == BLOCK_SIZE) {
334 if (++dirIdx < directory.length)
335 block = directory[dirIdx];
336 else
337 block = null;
338 blkIdx = 0;
339 }
340 index++;
341 return res;
342 }
343
344 @Override
345 public void remove() {
346 if (index == 0)
347 throw new IllegalStateException();
348
349 BlockList.this.remove(--index);
350
351 dirIdx = toDirectoryIndex(index);
352 blkIdx = toBlockIndex(index);
353 block = directory[dirIdx];
354 }
355 }
356 }