22// The .NET Foundation licenses this file to you under the MIT license.
33
44using System . Diagnostics ;
5- using System . Runtime . CompilerServices ;
65
76namespace System . Collections . Generic
87{
@@ -12,9 +11,7 @@ namespace System.Collections.Generic
1211 /// <typeparam name="T">The element type.</typeparam>
1312 internal struct ArrayBuilder < T >
1413 {
15- private InlineArray16 < T > _stackAllocatedBuffer = default ;
16- private const int StackAllocatedCapacity = 16 ;
17- private const int DefaultHeapCapacity = 4 ;
14+ private const int DefaultCapacity = 4 ;
1815
1916 private T [ ] ? _array ; // Starts out null, initialized on first Add.
2017 private int _count ; // Number of items into _array we're using.
@@ -26,17 +23,20 @@ internal struct ArrayBuilder<T>
2623 public ArrayBuilder ( int capacity ) : this ( )
2724 {
2825 Debug . Assert ( capacity >= 0 ) ;
29- if ( capacity > StackAllocatedCapacity )
26+ if ( capacity > 0 )
3027 {
31- _array = new T [ capacity - StackAllocatedCapacity ] ;
28+ _array = new T [ capacity ] ;
3229 }
3330 }
3431
3532 /// <summary>
3633 /// Gets the number of items this instance can store without re-allocating,
3734 /// or 0 if the backing array is <c>null</c>.
3835 /// </summary>
39- public int Capacity => _array ? . Length + StackAllocatedCapacity ?? StackAllocatedCapacity ;
36+ public int Capacity => _array ? . Length ?? 0 ;
37+
38+ /// <summary>Gets the current underlying array.</summary>
39+ public T [ ] ? Buffer => _array ;
4040
4141 /// <summary>
4242 /// Gets the number of items in the array currently in use.
@@ -52,7 +52,7 @@ public T this[int index]
5252 get
5353 {
5454 Debug . Assert ( index >= 0 && index < _count ) ;
55- return index < StackAllocatedCapacity ? _stackAllocatedBuffer [ index ] : _array ! [ index - StackAllocatedCapacity ] ;
55+ return _array ! [ index ] ;
5656 }
5757 }
5858
@@ -76,7 +76,7 @@ public void Add(T item)
7676 public T First ( )
7777 {
7878 Debug . Assert ( _count > 0 ) ;
79- return _stackAllocatedBuffer [ 0 ] ;
79+ return _array ! [ 0 ] ;
8080 }
8181
8282 /// <summary>
@@ -85,7 +85,7 @@ public T First()
8585 public T Last ( )
8686 {
8787 Debug . Assert ( _count > 0 ) ;
88- return _count <= StackAllocatedCapacity ? _stackAllocatedBuffer [ _count - 1 ] : _array ! [ _count - StackAllocatedCapacity - 1 ] ;
88+ return _array ! [ _count - 1 ] ;
8989 }
9090
9191 /// <summary>
@@ -101,19 +101,17 @@ public T[] ToArray()
101101 return Array . Empty < T > ( ) ;
102102 }
103103
104- T [ ] result = new T [ _count ] ;
105- int index = 0 ;
106- foreach ( T stackAllocatedValue in _stackAllocatedBuffer )
104+ Debug . Assert ( _array != null ) ; // Nonzero _count should imply this
105+
106+ T [ ] result = _array ;
107+ if ( _count < result . Length )
107108 {
108- result [ index ++ ] = stackAllocatedValue ;
109- if ( index >= _count )
110- {
111- return result ;
112- }
109+ // Avoid a bit of overhead (method call, some branches, extra codegen)
110+ // which would be incurred by using Array.Resize
111+ result = new T [ _count ] ;
112+ Array . Copy ( _array , result , _count ) ;
113113 }
114114
115- _array . AsSpan ( 0 , _count - StackAllocatedCapacity ) . CopyTo ( result . AsSpan ( start : StackAllocatedCapacity ) ) ;
116-
117115#if DEBUG
118116 // Try to prevent callers from using the ArrayBuilder after ToArray, if _count != 0.
119117 _count = - 1 ;
@@ -134,42 +132,25 @@ public T[] ToArray()
134132 public void UncheckedAdd ( T item )
135133 {
136134 Debug . Assert ( _count < Capacity ) ;
137- if ( _count < StackAllocatedCapacity )
138- {
139- _stackAllocatedBuffer [ _count ++ ] = item ;
140- }
141- else
142- {
143- _array ! [ _count ++ - StackAllocatedCapacity ] = item ;
144- }
135+
136+ _array ! [ _count ++ ] = item ;
145137 }
146138
147139 private void EnsureCapacity ( int minimum )
148140 {
149141 Debug . Assert ( minimum > Capacity ) ;
150142
151- if ( minimum < StackAllocatedCapacity )
152- {
153- return ;
154- }
155-
156- if ( _array == null )
157- {
158- // Initial capacity has not been set correctly, we will use the default size
159- _array = new T [ DefaultHeapCapacity ] ;
160- return ;
161- }
162-
163- int nextHeapCapacity = 2 * _array . Length ;
143+ int capacity = Capacity ;
144+ int nextCapacity = capacity == 0 ? DefaultCapacity : 2 * capacity ;
164145
165- if ( ( uint ) nextHeapCapacity > ( uint ) Array . MaxLength )
146+ if ( ( uint ) nextCapacity > ( uint ) Array . MaxLength )
166147 {
167- nextHeapCapacity = Math . Max ( _array . Length + 1 , Array . MaxLength ) ;
148+ nextCapacity = Math . Max ( capacity + 1 , Array . MaxLength ) ;
168149 }
169150
170- nextHeapCapacity = Math . Max ( nextHeapCapacity , minimum ) ;
151+ nextCapacity = Math . Max ( nextCapacity , minimum ) ;
171152
172- T [ ] next = new T [ nextHeapCapacity ] ;
153+ T [ ] next = new T [ nextCapacity ] ;
173154 if ( _count > 0 )
174155 {
175156 Array . Copy ( _array ! , next , _count ) ;
0 commit comments