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