2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
// See the LICENSE file in the project root for more information.
4
4
5
+ // This file is ported and adapted from ComputeSharp (Sergio0694/ComputeSharp),
6
+ // more info in ThirdPartyNotices.txt in the root of the project.
7
+
5
8
using System ;
6
9
using System . Collections . Immutable ;
10
+ using System . Runtime . CompilerServices ;
7
11
8
12
namespace CommunityToolkit . Mvvm . SourceGenerators . Helpers ;
9
13
10
14
/// <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.
12
16
/// </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
15
19
{
16
20
/// <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.
18
22
/// </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 ( ) ) ;
20
24
21
25
/// <summary>
22
- /// The rented <see cref="ImmutableArray{T}.Builder "/> instance to use.
26
+ /// The rented <see cref="Writer "/> instance to use.
23
27
/// </summary>
24
- private ImmutableArray < T > . Builder ? builder ;
28
+ private Writer ? writer ;
25
29
26
30
/// <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 .
28
32
/// </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>
30
34
public static ImmutableArrayBuilder < T > Rent ( )
31
35
{
32
- return new ( sharedObjectPool . Allocate ( ) ) ;
36
+ return new ( SharedObjectPool . Allocate ( ) ) ;
33
37
}
34
38
35
39
/// <summary>
36
40
/// Creates a new <see cref="ImmutableArrayBuilder{T}"/> object with the specified parameters.
37
41
/// </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 )
40
44
{
41
- this . builder = builder ;
45
+ this . writer = writer ;
42
46
}
43
47
44
48
/// <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
46
59
{
47
- get => this . builder ! . Count ;
60
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
61
+ get => this . writer ! . WrittenSpan ;
48
62
}
49
63
50
64
/// <inheritdoc cref="ImmutableArray{T}.Builder.Add(T)"/>
51
65
public readonly void Add ( T item )
52
66
{
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 ) ;
54
77
}
55
78
56
79
/// <inheritdoc cref="ImmutableArray{T}.Builder.ToImmutable"/>
57
80
public readonly ImmutableArray < T > ToImmutable ( )
58
81
{
59
- return this . builder ! . ToImmutable ( ) ;
82
+ T [ ] array = this . writer ! . WrittenSpan . ToArray ( ) ;
83
+
84
+ return Unsafe . As < T [ ] , ImmutableArray < T > > ( ref array ) ;
60
85
}
61
86
62
87
/// <inheritdoc cref="ImmutableArray{T}.Builder.ToArray"/>
63
88
public readonly T [ ] ToArray ( )
64
89
{
65
- return this . builder ! . ToArray ( ) ;
90
+ return this . writer ! . WrittenSpan . ToArray ( ) ;
66
91
}
67
92
68
- /// <inheritdoc cref="IDisposable.Dispose"/>
93
+ /// <inheritdoc/>
94
+ public override readonly string ToString ( )
95
+ {
96
+ return this . writer ! . WrittenSpan . ToString ( ) ;
97
+ }
98
+
99
+ /// <inheritdoc/>
69
100
public void Dispose ( )
70
101
{
71
- ImmutableArray < T > . Builder ? builder = this . builder ;
102
+ Writer ? writer = this . writer ;
72
103
73
- this . builder = null ;
104
+ this . writer = null ;
74
105
75
- if ( builder is not null )
106
+ if ( writer is not null )
76
107
{
77
- builder . Clear ( ) ;
108
+ writer . Clear ( ) ;
78
109
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 ) ;
80
158
}
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" ) ;
81
234
}
82
235
}
0 commit comments