Repository navigation
Expand file tree
/
Copy pathArrayBuilder.cs
More file actions
161 lines (137 loc) · 4.74 KB
/
Copy pathArrayBuilder.cs
File metadata and controls
161 lines (137 loc) · 4.74 KB
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
namespace System.Collections.Generic
{
/// <summary>
/// Helper type for avoiding allocations while building arrays.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
internal struct ArrayBuilder<T>
{
private const int DefaultCapacity = 4;
private T[]? _array; // Starts out null, initialized on first Add.
private int _count; // Number of items into _array we're using.
/// <summary>
/// Initializes the <see cref="ArrayBuilder{T}"/> with a specified capacity.
/// </summary>
/// <param name="capacity">The capacity of the array to allocate.</param>
public ArrayBuilder(int capacity) : this()
{
Debug.Assert(capacity >= 0);
if (capacity > 0)
{
_array = new T[capacity];
}
}
/// <summary>
/// Gets the number of items this instance can store without re-allocating,
/// or 0 if the backing array is <c>null</c>.
/// </summary>
public int Capacity => _array?.Length ?? 0;
/// <summary>Gets the current underlying array.</summary>
public T[]? Buffer => _array;
/// <summary>
/// Gets the number of items in the array currently in use.
/// </summary>
public int Count => _count;
/// <summary>
/// Gets or sets the item at a certain index in the array.
/// </summary>
/// <param name="index">The index into the array.</param>
public T this[int index]
{
get
{
Debug.Assert(index >= 0 && index < _count);
return _array![index];
}
}
/// <summary>
/// Adds an item to the backing array, resizing it if necessary.
/// </summary>
/// <param name="item">The item to add.</param>
public void Add(T item)
{
if (_count == Capacity)
{
EnsureCapacity(_count + 1);
}
UncheckedAdd(item);
}
/// <summary>
/// Gets the first item in this builder.
/// </summary>
public T First()
{
Debug.Assert(_count > 0);
return _array![0];
}
/// <summary>
/// Gets the last item in this builder.
/// </summary>
public T Last()
{
Debug.Assert(_count > 0);
return _array![_count - 1];
}
/// <summary>
/// Creates an array from the contents of this builder.
/// </summary>
/// <remarks>
/// Do not call this method twice on the same builder.
/// </remarks>
public T[] ToArray()
{
if (_count == 0)
{
return [];
}
Debug.Assert(_array != null); // Nonzero _count should imply this
T[] result = _array;
if (_count < result.Length)
{
// Avoid a bit of overhead (method call, some branches, extra codegen)
// which would be incurred by using Array.Resize
result = new T[_count];
Array.Copy(_array, result, _count);
}
#if DEBUG
// Try to prevent callers from using the ArrayBuilder after ToArray, if _count != 0.
_count = -1;
_array = null;
#endif
return result;
}
/// <summary>
/// Adds an item to the backing array, without checking if there is room.
/// </summary>
/// <param name="item">The item to add.</param>
/// <remarks>
/// Use this method if you know there is enough space in the <see cref="ArrayBuilder{T}"/>
/// for another item, and you are writing performance-sensitive code.
/// </remarks>
public void UncheckedAdd(T item)
{
Debug.Assert(_count < Capacity);
_array![_count++] = item;
}
private void EnsureCapacity(int minimum)
{
Debug.Assert(minimum > Capacity);
int capacity = Capacity;
int nextCapacity = capacity == 0 ? DefaultCapacity : 2 * capacity;
if ((uint)nextCapacity > (uint)Array.MaxLength)
{
nextCapacity = Math.Max(capacity + 1, Array.MaxLength);
}
nextCapacity = Math.Max(nextCapacity, minimum);
T[] next = new T[nextCapacity];
if (_count > 0)
{
Array.Copy(_array!, next, _count);
}
_array = next;
}
}
}