2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50
/// <summary>Random access list that allocates entries in blocks.</summary>
52
/// Random access list that allocates entries in blocks.
55
/// <see cref="System.Collections.ArrayList{E}">System.Collections.ArrayList<E>
57
/// , this type does not need to reallocate the
58
/// internal array in order to expand the capacity of the list. Access to any
59
/// element is constant time, but requires two array lookups instead of one.
61
/// To handle common usages,
62
/// <see cref="BlockList{T}.AddItem(object)">BlockList<T>.AddItem(object)</see>
64
/// <see cref="BlockList{T}.Iterator()">BlockList<T>.Iterator()</see>
66
/// internal code paths to amortize out the second array lookup, making addition
67
/// and simple iteration closer to one array operation per element processed.
70
/// <code>ArrayList</code>
71
/// , adding or removing from any position except the
72
/// end of the list requires O(N) time to copy all elements between the
73
/// modification point and the end of the list. Applications are strongly
74
/// encouraged to not use this access pattern with this list implementation.
77
public class BlockList<T> : AbstractList<T>
79
private const int BLOCK_BITS = 10;
81
internal const int BLOCK_SIZE = 1 << BLOCK_BITS;
83
private const int BLOCK_MASK = BLOCK_SIZE - 1;
85
private T[][] directory;
89
private int tailDirIdx;
91
private int tailBlkIdx;
93
private T[] tailBlock;
95
/// <summary>Initialize an empty list.</summary>
96
/// <remarks>Initialize an empty list.</remarks>
99
directory = NGit.Util.BlockList<T>.NewDirectory(256);
100
directory[0] = NGit.Util.BlockList<T>.NewBlock();
101
tailBlock = directory[0];
104
/// <summary>Initialize an empty list with an expected capacity.</summary>
105
/// <remarks>Initialize an empty list with an expected capacity.</remarks>
106
/// <param name="capacity">number of elements expected to be in the list.</param>
107
public BlockList(int capacity)
109
int dirSize = ToDirectoryIndex(capacity);
110
if ((capacity & BLOCK_MASK) != 0 || dirSize == 0)
114
directory = NGit.Util.BlockList<T>.NewDirectory(dirSize);
115
directory[0] = NGit.Util.BlockList<T>.NewBlock();
116
tailBlock = directory[0];
119
public override int Count
127
public override void Clear()
129
foreach (T[] block in directory)
133
Arrays.Fill(block, default(T));
139
tailBlock = directory[0];
142
public override T Get(int index)
144
if (index < 0 || size <= index)
146
throw new IndexOutOfRangeException(index.ToString());
148
return directory[ToDirectoryIndex(index)][ToBlockIndex(index)];
151
public override T Set(int index, T element)
153
if (index < 0 || size <= index)
155
throw new IndexOutOfRangeException(index.ToString());
157
T[] blockRef = directory[ToDirectoryIndex(index)];
158
int blockIdx = ToBlockIndex(index);
159
T old = blockRef[blockIdx];
160
blockRef[blockIdx] = element;
164
/// <summary>Quickly append all elements of another BlockList.</summary>
165
/// <remarks>Quickly append all elements of another BlockList.</remarks>
166
/// <param name="src">the list to copy elements from.</param>
167
public virtual void AddAll(NGit.Util.BlockList<T> src)
174
for (; srcDirIdx < src.tailDirIdx; srcDirIdx++)
176
AddAll(src.directory[srcDirIdx], 0, BLOCK_SIZE);
178
if (src.tailBlkIdx != 0)
180
AddAll(src.tailBlock, 0, src.tailBlkIdx);
184
/// <summary>Quickly append all elements from an array.</summary>
185
/// <remarks>Quickly append all elements from an array.</remarks>
186
/// <param name="src">the source array.</param>
187
/// <param name="srcIdx">first index to copy.</param>
188
/// <param name="srcCnt">number of elements to copy.</param>
189
public virtual void AddAll(T[] src, int srcIdx, int srcCnt)
194
int n = Math.Min(srcCnt, BLOCK_SIZE - i);
197
// Our tail is full, expand by one.
198
AddItem(src[srcIdx++]);
202
System.Array.Copy(src, srcIdx, tailBlock, i, n);
210
public override bool AddItem(T element)
215
// Fast-path: Append to current tail block.
216
tailBlock[i] = element;
221
// Slow path: Move to the next block, expanding if necessary.
222
if (++tailDirIdx == directory.Length)
224
T[][] newDir = NGit.Util.BlockList<T>.NewDirectory(directory.Length << 1);
225
System.Array.Copy(directory, 0, newDir, 0, directory.Length);
228
T[] blockRef = directory[tailDirIdx];
229
if (blockRef == null)
231
blockRef = NGit.Util.BlockList<T>.NewBlock();
232
directory[tailDirIdx] = blockRef;
234
blockRef[0] = element;
235
tailBlock = blockRef;
241
public override void Add(int index, T element)
245
// Fast-path: append onto the end of the list.
250
if (index < 0 || size < index)
252
throw new IndexOutOfRangeException(index.ToString());
256
// Slow-path: the list needs to expand and insert.
257
// Do this the naive way, callers shouldn't abuse
258
// this class by entering this code path.
261
// expand the list by one
262
for (int oldIdx = size - 2; index <= oldIdx; oldIdx--)
264
Set(oldIdx + 1, this[oldIdx]);
271
public override T Remove(int index)
273
if (index == size - 1)
275
// Fast-path: remove the last element.
276
T[] blockRef = directory[ToDirectoryIndex(index)];
277
int blockIdx = ToBlockIndex(index);
278
T old = blockRef[blockIdx];
279
blockRef[blockIdx] = default(T);
293
if (index < 0 || size <= index)
295
throw new IndexOutOfRangeException(index.ToString());
299
// Slow-path: the list needs to contract and remove.
300
// Do this the naive way, callers shouldn't abuse
301
// this class by entering this code path.
304
for (; index < size - 1; index++)
306
Set(index, this[index + 1]);
308
Set(size - 1, default(T));
316
private void ResetTailBlock()
318
tailDirIdx = ToDirectoryIndex(size);
319
tailBlkIdx = ToBlockIndex(size);
320
tailBlock = directory[tailDirIdx];
323
public override Sharpen.Iterator<T> Iterator()
325
return new BlockList<T>.MyIterator(this);
328
private static int ToDirectoryIndex(int index)
330
return (int)(((uint)index) >> BLOCK_BITS);
333
private static int ToBlockIndex(int index)
335
return index & BLOCK_MASK;
338
private static T[][] NewDirectory(int size)
340
return new T[size][];
343
private static T[] NewBlock()
345
return new T[BLOCK_SIZE];
348
private class MyIterator : Iterator<T>
358
public override bool HasNext()
360
return this.index < this._enclosing.size;
363
public override T Next()
365
if (this._enclosing.size <= this.index)
367
throw new NoSuchElementException();
369
T res = this.block[this.blkIdx];
370
if (++this.blkIdx == BlockList<T>.BLOCK_SIZE)
372
if (++this.dirIdx < this._enclosing.directory.Length)
374
this.block = this._enclosing.directory[this.dirIdx];
386
public override void Remove()
390
throw new InvalidOperationException();
392
this._enclosing.Remove(--this.index);
393
this.dirIdx = BlockList<T>.ToDirectoryIndex(this.index);
394
this.blkIdx = BlockList<T>.ToBlockIndex(this.index);
395
this.block = this._enclosing.directory[this.dirIdx];
398
internal MyIterator(BlockList<T> _enclosing)
400
this._enclosing = _enclosing;
401
block = this._enclosing.directory[0];
404
private readonly BlockList<T> _enclosing;