1+ // Licensed to the .NET Foundation under one or more agreements.
2+ // The .NET Foundation licenses this file to you under the MIT license.
3+ // See the LICENSE file in the project root for more information.
4+
5+ using System ;
6+ using System . Buffers ;
7+ using System . Diagnostics . Contracts ;
8+ using System . Runtime . CompilerServices ;
9+
10+ namespace Microsoft . Toolkit . Uwp . UI . Helpers . Internals
11+ {
12+ /// <summary>
13+ /// A simple buffer writer implementation using pooled arrays.
14+ /// </summary>
15+ /// <typeparam name="T">The type of items to store in the list.</typeparam>
16+ /// <remarks>
17+ /// This type is a <see langword="ref"/> <see langword="struct"/> to avoid the object allocation and to
18+ /// enable the pattern-based <see cref="IDisposable"/> support. We aren't worried with consumers not
19+ /// using this type correctly since it's private and only accessible within the parent type.
20+ /// </remarks>
21+ internal ref struct ArrayPoolBufferWriter < T >
22+ {
23+ /// <summary>
24+ /// The default buffer size to use to expand empty arrays.
25+ /// </summary>
26+ private const int DefaultInitialBufferSize = 128 ;
27+
28+ /// <summary>
29+ /// The underlying <typeparamref name="T"/> array.
30+ /// </summary>
31+ private T [ ] array ;
32+
33+ /// <summary>
34+ /// The starting offset within <see cref="array"/>.
35+ /// </summary>
36+ private int index ;
37+
38+ /// <summary>
39+ /// Creates a new instance of the <see cref="ArrayPoolBufferWriter{T}"/> struct.
40+ /// </summary>
41+ /// <returns>A new <see cref="ArrayPoolBufferWriter{T}"/> instance.</returns>
42+ [ Pure ]
43+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
44+ public static ArrayPoolBufferWriter < T > Create ( )
45+ {
46+ return new ( ) { array = ArrayPool < T > . Shared . Rent ( DefaultInitialBufferSize ) } ;
47+ }
48+
49+ /// <summary>
50+ /// Gets the total number of items stored in the current instance.
51+ /// </summary>
52+ public int Count
53+ {
54+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
55+ get => this . array . Length ;
56+ }
57+
58+ /// <summary>
59+ /// Gets the item at the specified offset into the current buffer in use.
60+ /// </summary>
61+ /// <param name="index">The index of the element to retrieve.</param>
62+ /// <returns>The item at the specified offset into the current buffer in use.</returns>
63+ /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="index"/> is out of range.</exception>
64+ public T this [ int index ]
65+ {
66+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
67+ get
68+ {
69+ if ( ( uint ) index >= this . index )
70+ {
71+ static void Throw ( ) => throw new ArgumentOutOfRangeException ( nameof ( index ) ) ;
72+
73+ Throw ( ) ;
74+ }
75+
76+ return this . array [ index ] ;
77+ }
78+ }
79+
80+ /// <summary>
81+ /// Adds a new item to the current collection.
82+ /// </summary>
83+ /// <param name="item">The item to add.</param>
84+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
85+ public void Add ( T item )
86+ {
87+ if ( this . index == this . array . Length )
88+ {
89+ ResizeBuffer ( ) ;
90+ }
91+
92+ this . array [ this . index ++ ] = item ;
93+ }
94+
95+ /// <summary>
96+ /// Resets the underlying array and the stored items.
97+ /// </summary>
98+ public void Reset ( )
99+ {
100+ Array . Clear ( this . array , 0 , this . index ) ;
101+
102+ this . index = 0 ;
103+ }
104+
105+ /// <summary>
106+ /// Resizes <see cref="array"/> when there is no space left for new items.
107+ /// </summary>
108+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
109+ private void ResizeBuffer ( )
110+ {
111+ T [ ] rent = ArrayPool < T > . Shared . Rent ( this . index << 2 ) ;
112+
113+ Array . Copy ( this . array , 0 , rent , 0 , this . index ) ;
114+ Array . Clear ( this . array , 0 , this . index ) ;
115+
116+ ArrayPool < T > . Shared . Return ( this . array ) ;
117+
118+ this . array = rent ;
119+ }
120+
121+ /// <inheritdoc cref="IDisposable.Dispose"/>
122+ public void Dispose ( )
123+ {
124+ Array . Clear ( this . array , 0 , this . index ) ;
125+
126+ ArrayPool < T > . Shared . Return ( this . array ) ;
127+ }
128+ }
129+ }
0 commit comments