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