6
6
// more info in ThirdPartyNotices.txt in the root of the project.
7
7
8
8
using System ;
9
+ using System . Buffers ;
9
10
using System . Collections . Immutable ;
11
+ using System . Diagnostics . CodeAnalysis ;
10
12
using System . Runtime . CompilerServices ;
11
13
12
14
namespace CommunityToolkit . Mvvm . SourceGenerators . Helpers ;
@@ -15,13 +17,8 @@ namespace CommunityToolkit.Mvvm.SourceGenerators.Helpers;
15
17
/// A helper type to build sequences of values with pooled buffers.
16
18
/// </summary>
17
19
/// <typeparam name="T">The type of items to create sequences for.</typeparam>
18
- internal struct ImmutableArrayBuilder < T > : IDisposable
20
+ internal ref struct ImmutableArrayBuilder < T >
19
21
{
20
- /// <summary>
21
- /// The shared <see cref="ObjectPool{T}"/> instance to share <see cref="Writer"/> objects.
22
- /// </summary>
23
- private static readonly ObjectPool < Writer > SharedObjectPool = new ( static ( ) => new Writer ( ) ) ;
24
-
25
22
/// <summary>
26
23
/// The rented <see cref="Writer"/> instance to use.
27
24
/// </summary>
@@ -33,7 +30,7 @@ internal struct ImmutableArrayBuilder<T> : IDisposable
33
30
/// <returns>A <see cref="ImmutableArrayBuilder{T}"/> instance to write data to.</returns>
34
31
public static ImmutableArrayBuilder < T > Rent ( )
35
32
{
36
- return new ( SharedObjectPool . Allocate ( ) ) ;
33
+ return new ( new Writer ( ) ) ;
37
34
}
38
35
39
36
/// <summary>
@@ -46,7 +43,7 @@ private ImmutableArrayBuilder(Writer writer)
46
43
}
47
44
48
45
/// <inheritdoc cref="ImmutableArray{T}.Builder.Count"/>
49
- public int Count
46
+ public readonly int Count
50
47
{
51
48
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
52
49
get => this . writer ! . Count ;
@@ -55,6 +52,7 @@ public int Count
55
52
/// <summary>
56
53
/// Gets the data written to the underlying buffer so far, as a <see cref="ReadOnlySpan{T}"/>.
57
54
/// </summary>
55
+ [ UnscopedRef ]
58
56
public readonly ReadOnlySpan < T > WrittenSpan
59
57
{
60
58
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -71,7 +69,7 @@ public readonly void Add(T item)
71
69
/// Adds the specified items to the end of the array.
72
70
/// </summary>
73
71
/// <param name="items">The items to add at the end of the array.</param>
74
- public readonly void AddRange ( ReadOnlySpan < T > items )
72
+ public readonly void AddRange ( scoped ReadOnlySpan < T > items )
75
73
{
76
74
this . writer ! . AddRange ( items ) ;
77
75
}
@@ -96,30 +94,25 @@ public override readonly string ToString()
96
94
return this . writer ! . WrittenSpan . ToString ( ) ;
97
95
}
98
96
99
- /// <inheritdoc/>
97
+ /// <inheritdoc cref="IDisposable.Dispose" />
100
98
public void Dispose ( )
101
99
{
102
100
Writer ? writer = this . writer ;
103
101
104
102
this . writer = null ;
105
103
106
- if ( writer is not null )
107
- {
108
- writer . Clear ( ) ;
109
-
110
- SharedObjectPool . Free ( writer ) ;
111
- }
104
+ writer ? . Dispose ( ) ;
112
105
}
113
106
114
107
/// <summary>
115
108
/// A class handling the actual buffer writing.
116
109
/// </summary>
117
- private sealed class Writer
110
+ private sealed class Writer : IDisposable
118
111
{
119
112
/// <summary>
120
113
/// The underlying <typeparamref name="T"/> array.
121
114
/// </summary>
122
- private T [ ] array ;
115
+ private T ? [ ] ? array ;
123
116
124
117
/// <summary>
125
118
/// The starting offset within <see cref="array"/>.
@@ -131,15 +124,7 @@ private sealed class Writer
131
124
/// </summary>
132
125
public Writer ( )
133
126
{
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
-
127
+ this . array = ArrayPool < T ? > . Shared . Rent ( typeof ( T ) == typeof ( char ) ? 1024 : 8 ) ;
143
128
this . index = 0 ;
144
129
}
145
130
@@ -154,38 +139,38 @@ public int Count
154
139
public ReadOnlySpan < T > WrittenSpan
155
140
{
156
141
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
157
- get => new ( this . array , 0 , this . index ) ;
142
+ get => new ( this . array ! , 0 , this . index ) ;
158
143
}
159
144
160
145
/// <inheritdoc cref="ImmutableArrayBuilder{T}.Add"/>
161
146
public void Add ( T value )
162
147
{
163
148
EnsureCapacity ( 1 ) ;
164
149
165
- this . array [ this . index ++ ] = value ;
150
+ this . array ! [ this . index ++ ] = value ;
166
151
}
167
152
168
153
/// <inheritdoc cref="ImmutableArrayBuilder{T}.AddRange"/>
169
154
public void AddRange ( ReadOnlySpan < T > items )
170
155
{
171
156
EnsureCapacity ( items . Length ) ;
172
157
173
- items . CopyTo ( this . array . AsSpan ( this . index ) ) ;
158
+ items . CopyTo ( this . array . AsSpan ( this . index ) ! ) ;
174
159
175
160
this . index += items . Length ;
176
161
}
177
162
178
- /// <summary>
179
- /// Clears the items in the current writer.
180
- /// </summary>
181
- public void Clear ( )
163
+ /// <inheritdoc/>
164
+ public void Dispose ( )
182
165
{
183
- if ( typeof ( T ) != typeof ( char ) )
166
+ T ? [ ] ? array = this . array ;
167
+
168
+ this . array = null ;
169
+
170
+ if ( array is not null )
184
171
{
185
- this . array . AsSpan ( 0 , this . index ) . Clear ( ) ;
172
+ ArrayPool < T ? > . Shared . Return ( array , clearArray : typeof ( T ) != typeof ( char ) ) ;
186
173
}
187
-
188
- this . index = 0 ;
189
174
}
190
175
191
176
/// <summary>
@@ -195,7 +180,7 @@ public void Clear()
195
180
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
196
181
private void EnsureCapacity ( int requestedSize )
197
182
{
198
- if ( requestedSize > this . array . Length - this . index )
183
+ if ( requestedSize > this . array ! . Length - this . index )
199
184
{
200
185
ResizeBuffer ( requestedSize ) ;
201
186
}
@@ -209,13 +194,15 @@ private void EnsureCapacity(int requestedSize)
209
194
private void ResizeBuffer ( int sizeHint )
210
195
{
211
196
int minimumSize = this . index + sizeHint ;
212
- int requestedSize = Math . Max ( this . array . Length * 2 , minimumSize ) ;
213
197
214
- T [ ] newArray = new T [ requestedSize ] ;
198
+ T ? [ ] oldArray = this . array ! ;
199
+ T ? [ ] newArray = ArrayPool < T ? > . Shared . Rent ( minimumSize ) ;
215
200
216
- Array . Copy ( this . array , newArray , this . index ) ;
201
+ Array . Copy ( oldArray , newArray , this . index ) ;
217
202
218
203
this . array = newArray ;
204
+
205
+ ArrayPool < T ? > . Shared . Return ( oldArray , clearArray : typeof ( T ) != typeof ( char ) ) ;
219
206
}
220
207
}
221
208
}
0 commit comments