22// The .NET Foundation licenses this file to you under the MIT license.
33// See the LICENSE file in the project root for more information.
44
5+ // This file is ported and adapted from ComputeSharp (Sergio0694/ComputeSharp),
6+ // more info in ThirdPartyNotices.txt in the root of the project.
7+
58using System ;
69using System . Collections . Immutable ;
10+ using System . Runtime . CompilerServices ;
711
812namespace CommunityToolkit . Mvvm . SourceGenerators . Helpers ;
913
1014/// <summary>
11- /// A helper type to build <see cref="ImmutableArray{T}"/> instances with pooled buffers.
15+ /// A helper type to build sequences of values with pooled buffers.
1216/// </summary>
13- /// <typeparam name="T">The type of items to create arrays for.</typeparam>
14- internal ref struct ImmutableArrayBuilder < T >
17+ /// <typeparam name="T">The type of items to create sequences for.</typeparam>
18+ internal struct ImmutableArrayBuilder < T > : IDisposable
1519{
1620 /// <summary>
17- /// The shared <see cref="ObjectPool{T}"/> instance to share <see cref="ImmutableArray{T}.Builder "/> objects.
21+ /// The shared <see cref="ObjectPool{T}"/> instance to share <see cref="Writer "/> objects.
1822 /// </summary>
19- private static readonly ObjectPool < ImmutableArray < T > . Builder > sharedObjectPool = new ( ImmutableArray . CreateBuilder < T > ) ;
23+ private static readonly ObjectPool < Writer > SharedObjectPool = new ( static ( ) => new Writer ( ) ) ;
2024
2125 /// <summary>
22- /// The rented <see cref="ImmutableArray{T}.Builder "/> instance to use.
26+ /// The rented <see cref="Writer "/> instance to use.
2327 /// </summary>
24- private ImmutableArray < T > . Builder ? builder ;
28+ private Writer ? writer ;
2529
2630 /// <summary>
27- /// Rents a new pooled <see cref="ImmutableArray {T}.Builder "/> instance through a new <see cref="ImmutableArrayBuilder{T}"/> value .
31+ /// Creates a <see cref="ImmutableArrayBuilder {T}"/> value with a pooled underlying data writer .
2832 /// </summary>
29- /// <returns>A <see cref="ImmutableArrayBuilder{T}"/> to interact with the underlying <see cref="ImmutableArray{T}.Builder"/> instance .</returns>
33+ /// <returns>A <see cref="ImmutableArrayBuilder{T}"/> instance to write data to .</returns>
3034 public static ImmutableArrayBuilder < T > Rent ( )
3135 {
32- return new ( sharedObjectPool . Allocate ( ) ) ;
36+ return new ( SharedObjectPool . Allocate ( ) ) ;
3337 }
3438
3539 /// <summary>
3640 /// Creates a new <see cref="ImmutableArrayBuilder{T}"/> object with the specified parameters.
3741 /// </summary>
38- /// <param name="builder"> </param>
39- private ImmutableArrayBuilder ( ImmutableArray < T > . Builder builder )
42+ /// <param name="writer">The target data writer to use. </param>
43+ private ImmutableArrayBuilder ( Writer writer )
4044 {
41- this . builder = builder ;
45+ this . writer = writer ;
4246 }
4347
4448 /// <inheritdoc cref="ImmutableArray{T}.Builder.Count"/>
45- public readonly int Count
49+ public int Count
50+ {
51+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
52+ get => this . writer ! . Count ;
53+ }
54+
55+ /// <summary>
56+ /// Gets the data written to the underlying buffer so far, as a <see cref="ReadOnlySpan{T}"/>.
57+ /// </summary>
58+ public readonly ReadOnlySpan < T > WrittenSpan
4659 {
47- get => this . builder ! . Count ;
60+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
61+ get => this . writer ! . WrittenSpan ;
4862 }
4963
5064 /// <inheritdoc cref="ImmutableArray{T}.Builder.Add(T)"/>
5165 public readonly void Add ( T item )
5266 {
53- this . builder ! . Add ( item ) ;
67+ this . writer ! . Add ( item ) ;
68+ }
69+
70+ /// <summary>
71+ /// Adds the specified items to the end of the array.
72+ /// </summary>
73+ /// <param name="items">The items to add at the end of the array.</param>
74+ public readonly void AddRange ( ReadOnlySpan < T > items )
75+ {
76+ this . writer ! . AddRange ( items ) ;
5477 }
5578
5679 /// <inheritdoc cref="ImmutableArray{T}.Builder.ToImmutable"/>
5780 public readonly ImmutableArray < T > ToImmutable ( )
5881 {
59- return this . builder ! . ToImmutable ( ) ;
82+ T [ ] array = this . writer ! . WrittenSpan . ToArray ( ) ;
83+
84+ return Unsafe . As < T [ ] , ImmutableArray < T > > ( ref array ) ;
6085 }
6186
6287 /// <inheritdoc cref="ImmutableArray{T}.Builder.ToArray"/>
6388 public readonly T [ ] ToArray ( )
6489 {
65- return this . builder ! . ToArray ( ) ;
90+ return this . writer ! . WrittenSpan . ToArray ( ) ;
6691 }
6792
68- /// <inheritdoc cref="IDisposable.Dispose"/>
93+ /// <inheritdoc/>
94+ public override readonly string ToString ( )
95+ {
96+ return this . writer ! . WrittenSpan . ToString ( ) ;
97+ }
98+
99+ /// <inheritdoc/>
69100 public void Dispose ( )
70101 {
71- ImmutableArray < T > . Builder ? builder = this . builder ;
102+ Writer ? writer = this . writer ;
72103
73- this . builder = null ;
104+ this . writer = null ;
74105
75- if ( builder is not null )
106+ if ( writer is not null )
76107 {
77- builder . Clear ( ) ;
108+ writer . Clear ( ) ;
78109
79- sharedObjectPool . Free ( builder ) ;
110+ SharedObjectPool . Free ( writer ) ;
111+ }
112+ }
113+
114+ /// <summary>
115+ /// A class handling the actual buffer writing.
116+ /// </summary>
117+ private sealed class Writer
118+ {
119+ /// <summary>
120+ /// The underlying <typeparamref name="T"/> array.
121+ /// </summary>
122+ private T [ ] array ;
123+
124+ /// <summary>
125+ /// The starting offset within <see cref="array"/>.
126+ /// </summary>
127+ private int index ;
128+
129+ /// <summary>
130+ /// Creates a new <see cref="Writer"/> instance with the specified parameters.
131+ /// </summary>
132+ public Writer ( )
133+ {
134+ if ( typeof ( T ) == typeof ( char ) )
135+ {
136+ this . array = new T [ 1024 ] ;
137+ }
138+ else
139+ {
140+ this . array = new T [ 8 ] ;
141+ }
142+
143+ this . index = 0 ;
144+ }
145+
146+ /// <inheritdoc cref="ImmutableArrayBuilder{T}.Count"/>
147+ public int Count
148+ {
149+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
150+ get => this . array ! . Length ;
151+ }
152+
153+ /// <inheritdoc cref="ImmutableArrayBuilder{T}.WrittenSpan"/>
154+ public ReadOnlySpan < T > WrittenSpan
155+ {
156+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
157+ get => new ( this . array , 0 , this . index ) ;
80158 }
159+
160+ /// <inheritdoc cref="ImmutableArrayBuilder{T}.Add"/>
161+ public void Add ( T value )
162+ {
163+ EnsureCapacity ( 1 ) ;
164+
165+ this . array [ this . index ++ ] = value ;
166+ }
167+
168+ /// <inheritdoc cref="ImmutableArrayBuilder{T}.AddRange"/>
169+ public void AddRange ( ReadOnlySpan < T > items )
170+ {
171+ EnsureCapacity ( items . Length ) ;
172+
173+ items . CopyTo ( this . array . AsSpan ( this . index ) ) ;
174+
175+ this . index += items . Length ;
176+ }
177+
178+ /// <summary>
179+ /// Clears the items in the current writer.
180+ /// </summary>
181+ public void Clear ( )
182+ {
183+ if ( typeof ( T ) != typeof ( char ) )
184+ {
185+ this . array . AsSpan ( 0 , this . index ) . Clear ( ) ;
186+ }
187+
188+ this . index = 0 ;
189+ }
190+
191+ /// <summary>
192+ /// Ensures that <see cref="array"/> has enough free space to contain a given number of new items.
193+ /// </summary>
194+ /// <param name="requestedSize">The minimum number of items to ensure space for in <see cref="array"/>.</param>
195+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
196+ private void EnsureCapacity ( int requestedSize )
197+ {
198+ if ( requestedSize > this . array . Length - this . index )
199+ {
200+ ResizeBuffer ( requestedSize ) ;
201+ }
202+ }
203+
204+ /// <summary>
205+ /// Resizes <see cref="array"/> to ensure it can fit the specified number of new items.
206+ /// </summary>
207+ /// <param name="sizeHint">The minimum number of items to ensure space for in <see cref="array"/>.</param>
208+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
209+ private void ResizeBuffer ( int sizeHint )
210+ {
211+ int minimumSize = this . index + sizeHint ;
212+ int requestedSize = Math . Max ( this . array . Length * 2 , minimumSize ) ;
213+
214+ T [ ] newArray = new T [ requestedSize ] ;
215+
216+ Array . Copy ( this . array , newArray , this . index ) ;
217+
218+ this . array = newArray ;
219+ }
220+ }
221+ }
222+
223+ /// <summary>
224+ /// Private helpers for the <see cref="ImmutableArrayBuilder{T}"/> type.
225+ /// </summary>
226+ file static class ImmutableArrayBuilder
227+ {
228+ /// <summary>
229+ /// Throws an <see cref="ArgumentOutOfRangeException"/> for <c>"index"</c>.
230+ /// </summary>
231+ public static void ThrowArgumentOutOfRangeExceptionForIndex ( )
232+ {
233+ throw new ArgumentOutOfRangeException ( "index" ) ;
81234 }
82235}
0 commit comments