1+ using System ;
2+ using System . Buffers ;
3+ using System . Runtime . CompilerServices ;
4+
5+ namespace PooledStream
6+ {
7+ public class PooledMemoryBufferWriter < T > : IDisposable , IBufferWriter < T > where T : struct
8+ {
9+ ArrayPool < T > _Pool ;
10+ T [ ] _currentBuffer ;
11+ int _Position ;
12+ int _Length ;
13+ const int DefaultSize = 1024 ;
14+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
15+ void Reallocate ( int sizeHint )
16+ {
17+ var nar = _Pool . Rent ( sizeHint ) ;
18+ if ( _currentBuffer != null )
19+ {
20+ Buffer . BlockCopy ( _currentBuffer , 0 , nar , 0 , _currentBuffer . Length < nar . Length ? _currentBuffer . Length : nar . Length ) ;
21+ _Pool . Return ( _currentBuffer ) ;
22+ }
23+ _currentBuffer = nar ;
24+ }
25+ /// <summary>
26+ /// use shared instance and preallocatedSize = 1024
27+ /// </summary>
28+ public PooledMemoryBufferWriter ( ) : this ( ArrayPool < T > . Shared )
29+ {
30+
31+ }
32+ /// <summary>
33+ /// use shared instance, use preallocateSize as reserved buffer length
34+ /// </summary>
35+ /// <param name="preallocateSize">initial reserved buffer size</param>
36+ public PooledMemoryBufferWriter ( int preallocateSize ) : this ( ArrayPool < T > . Shared , preallocateSize )
37+ {
38+
39+ }
40+ /// <summary>
41+ /// use pool for memory pool
42+ /// </summary>
43+ /// <param name="pool">memory pool</param>
44+ public PooledMemoryBufferWriter ( ArrayPool < T > pool ) : this ( pool , DefaultSize )
45+ {
46+ }
47+ /// <summary>
48+ /// </summary>
49+ /// <param name="pool">memory pool</param>
50+ /// <param name="preallocateSize">initial reserved buffer size</param>
51+ public PooledMemoryBufferWriter ( ArrayPool < T > pool , int preallocateSize )
52+ {
53+ if ( pool == null )
54+ {
55+ throw new ArgumentNullException ( nameof ( pool ) ) ;
56+ }
57+ if ( preallocateSize < 0 )
58+ {
59+ throw new ArgumentOutOfRangeException ( nameof ( preallocateSize ) , "size must be greater than 0" ) ;
60+ }
61+ _Pool = pool ;
62+ _currentBuffer = null ;
63+ _Position = 0 ;
64+ _Length = 0 ;
65+ Reallocate ( preallocateSize ) ;
66+ }
67+ /// <inheritdoc/>
68+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
69+ public void Advance ( int count )
70+ {
71+ if ( _Position + count > _currentBuffer . Length )
72+ {
73+ throw new ArgumentOutOfRangeException ( "advance too many(" + count . ToString ( ) + ")" ) ;
74+ }
75+ _Position += count ;
76+ if ( _Length < _Position )
77+ {
78+ _Length = _Position ;
79+ }
80+ }
81+
82+ /// <summary>return buffer to pool and reset buffer status</summary>
83+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
84+ public void Dispose ( )
85+ {
86+ if ( _currentBuffer != null )
87+ {
88+ _Pool . Return ( _currentBuffer ) ;
89+ _currentBuffer = null ;
90+ _Position = 0 ;
91+ _Length = 0 ;
92+ }
93+ }
94+
95+ /// <inheritdoc/>
96+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
97+ public Memory < T > GetMemory ( int sizeHint = 0 )
98+ {
99+ if ( sizeHint < 0 )
100+ {
101+ throw new ArgumentOutOfRangeException ( "sizeHint" , "size must be greater than 0" ) ;
102+ }
103+ if ( sizeHint == 0 )
104+ {
105+ sizeHint = DefaultSize ;
106+ }
107+ if ( _Position + sizeHint > _currentBuffer . Length )
108+ {
109+ Reallocate ( _Position + sizeHint ) ;
110+ }
111+ return _currentBuffer . AsMemory ( _Position , sizeHint ) ;
112+ }
113+ /// <inheritdoc/>
114+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
115+ public Span < T > GetSpan ( int sizeHint = 0 )
116+ {
117+ if ( sizeHint < 0 )
118+ {
119+ throw new ArgumentOutOfRangeException ( "sizeHint" , "size must be greater than 0" ) ;
120+ }
121+ if ( sizeHint == 0 )
122+ {
123+ sizeHint = DefaultSize ;
124+ }
125+ if ( _Position + sizeHint > _currentBuffer . Length )
126+ {
127+ Reallocate ( _Position + sizeHint ) ;
128+ }
129+ return _currentBuffer . AsSpan ( _Position , sizeHint ) ;
130+ }
131+ /// <summary>expose current buffer as Span</summary>
132+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
133+ public ReadOnlySpan < T > ToSpanUnsafe ( )
134+ {
135+ return _currentBuffer . AsSpan ( 0 , _Length ) ;
136+ }
137+ /// <summary>expose current buffer as Memory</summary>
138+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
139+ public ReadOnlyMemory < T > ToMemoryUnsafe ( )
140+ {
141+ return _currentBuffer . AsMemory ( 0 , _Length ) ;
142+ }
143+ /// <summary>reset buffer status, buffer will be reallocated</summary>
144+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
145+ public void Reset ( int preallocateSize )
146+ {
147+ if ( preallocateSize < 0 )
148+ {
149+ throw new ArgumentOutOfRangeException ( "preallocateSize" , "size must be greater than 0" ) ;
150+ }
151+ _Pool . Return ( _currentBuffer ) ;
152+ _currentBuffer = _Pool . Rent ( preallocateSize ) ;
153+ _Length = 0 ;
154+ _Position = 0 ;
155+ }
156+ /// <summary>reset buffer status, buffer will be reused</summary>
157+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
158+ public void Reset ( )
159+ {
160+ _Length = 0 ;
161+ _Position = 0 ;
162+ }
163+ }
164+ }
0 commit comments