@@ -3,7 +3,8 @@ namespace PooledStream
3
3
using System ;
4
4
using System . IO ;
5
5
using System . Buffers ;
6
- public partial class PooledMemoryStream : Stream
6
+ using System . Runtime . CompilerServices ;
7
+ public sealed partial class PooledMemoryStream : Stream
7
8
{
8
9
/// <summary>create writable memory stream with default parameters</summary>
9
10
/// <remarks>buffer is allocated from ArrayPool.Shared</remarks>
@@ -63,17 +64,25 @@ public override void Flush()
63
64
{
64
65
}
65
66
67
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
66
68
void ReallocateBuffer ( int minimumRequired )
67
69
{
68
70
var tmp = m_Pool . Rent ( minimumRequired ) ;
69
- #if NETSTANDARD2_1
70
- _currentbuffer . AsSpan ( ) . CopyTo ( tmp ) ;
71
- #else
72
- Buffer . BlockCopy ( _currentbuffer , 0 , tmp , 0 , _currentbuffer . Length ) ;
73
- #endif
74
- m_Pool . Return ( _currentbuffer ) ;
71
+ if ( _currentbuffer != null )
72
+ {
73
+ // #if NETSTANDARD2_1
74
+ // _currentbuffer.AsSpan().CopyTo(tmp);
75
+ // #else
76
+ // Buffer.BlockCopy(_currentbuffer, 0, tmp, 0, _currentbuffer.Length);
77
+ // #endif
78
+ Buffer . BlockCopy ( _currentbuffer , 0 , tmp , 0 , _currentbuffer . Length < tmp . Length ? _currentbuffer . Length : tmp . Length ) ;
79
+ m_Pool . Return ( _currentbuffer ) ;
80
+ }
75
81
_currentbuffer = tmp ;
76
82
}
83
+ /// <summary>set stream length</summary>
84
+ /// <remarks>if length is larger than current buffer length, re-allocating buffer</remarks>
85
+ /// <exception cref="System.InvalidOperationException">if stream is readonly</exception>
77
86
public override void SetLength ( long value )
78
87
{
79
88
if ( ! _CanWrite )
@@ -89,10 +98,21 @@ public override void SetLength(long value)
89
98
throw new IndexOutOfRangeException ( "underflow" ) ;
90
99
}
91
100
_Length = ( int ) value ;
92
- if ( _currentbuffer . Length < _Length )
101
+ if ( _currentbuffer == null || _currentbuffer . Length < _Length )
93
102
{
94
103
ReallocateBuffer ( ( int ) _Length ) ;
95
104
}
105
+ if ( _Position >= _Length )
106
+ {
107
+ if ( _Length == 0 )
108
+ {
109
+ _Position = 0 ;
110
+ }
111
+ else
112
+ {
113
+ _Position = _Length - 1 ;
114
+ }
115
+ }
96
116
}
97
117
protected override void Dispose ( bool disposing )
98
118
{
@@ -102,11 +122,18 @@ protected override void Dispose(bool disposing)
102
122
m_Pool . Return ( _currentbuffer ) ;
103
123
_currentbuffer = null ;
104
124
}
125
+ _Length = 0 ;
126
+ _Position = 0 ;
105
127
}
106
128
/// <summary>ensure the buffer size</summary>
107
129
/// <remarks>capacity != stream buffer length</remarks>
130
+ /// <exception cref="System.InvalidOperationException">if stream is readonly</exception>
108
131
public void Reserve ( int capacity )
109
132
{
133
+ if ( ! _CanWrite )
134
+ {
135
+ throw new InvalidOperationException ( "stream is readonly" ) ;
136
+ }
110
137
if ( capacity > _currentbuffer . Length )
111
138
{
112
139
ReallocateBuffer ( capacity ) ;
@@ -155,5 +182,88 @@ public override long Seek(long offset, SeekOrigin origin)
155
182
bool _CanWrite ;
156
183
int _Length ;
157
184
int _Position ;
185
+ public override int Read ( byte [ ] buffer , int offset , int count )
186
+ {
187
+ int readlen = count > ( int ) ( _Length - _Position ) ? ( int ) ( _Length - _Position ) : count ;
188
+ if ( readlen > 0 )
189
+ {
190
+ Buffer . BlockCopy ( _currentbuffer
191
+ , ( int ) _Position
192
+ , buffer , offset
193
+ , readlen )
194
+ ;
195
+ _Position += readlen ;
196
+ return readlen ;
197
+ }
198
+ else
199
+ {
200
+ return 0 ;
201
+ }
202
+ }
203
+
204
+ /// <summary>write data to stream</summary>
205
+ /// <remarks>if stream data length is over int.MaxValue, this method throws IndexOutOfRangeException</remarks>
206
+ /// <exception cref="System.InvalidOperationException">if stream is readonly</exception>
207
+ public override void Write ( byte [ ] buffer , int offset , int count )
208
+ {
209
+ if ( ! _CanWrite )
210
+ {
211
+ throw new InvalidOperationException ( "stream is readonly" ) ;
212
+ }
213
+ int endOffset = _Position + count ;
214
+ if ( _currentbuffer == null || endOffset > _currentbuffer . Length )
215
+ {
216
+ ReallocateBuffer ( ( int ) ( endOffset ) * 2 ) ;
217
+ }
218
+ Buffer . BlockCopy ( buffer , offset ,
219
+ _currentbuffer , ( int ) _Position , count ) ;
220
+ if ( endOffset > _Length )
221
+ {
222
+ _Length = endOffset ;
223
+ }
224
+ _Position = endOffset ;
225
+ }
226
+ /// <summary>shrink internal buffer by re-allocating memory</summary>
227
+ /// <remarks>if internal buffer is shorter than minimumRequired, nothing to do</remarks>
228
+ /// <exception cref="System.InvalidOperationException">if stream is readonly</exception>
229
+ public void Shrink ( int minimumRequired )
230
+ {
231
+ if ( ! _CanWrite )
232
+ {
233
+ throw new InvalidOperationException ( "stream is readonly" ) ;
234
+ }
235
+ if ( _currentbuffer == null )
236
+ {
237
+ return ;
238
+ }
239
+ if ( _currentbuffer . Length > minimumRequired )
240
+ {
241
+ ReallocateBuffer ( minimumRequired ) ;
242
+ }
243
+ if ( minimumRequired <= _Length )
244
+ {
245
+ _Length = minimumRequired ;
246
+ }
247
+ }
248
+ /// <summary>get internal data as Span</summary>
249
+ /// <remarks>you must not use returned value outside of stream's lifetime</remarks>
250
+ public ReadOnlySpan < byte > ToSpanUnsafe ( )
251
+ {
252
+ if ( _currentbuffer == null || _Length <= 0 )
253
+ {
254
+ return Span < byte > . Empty ;
255
+ }
256
+ return _currentbuffer . AsSpan ( 0 , _Length ) ;
257
+ }
258
+ /// <summary>get internal data as Memory</summary>
259
+ /// <remarks>you must not use returned value outside of stream's lifetime</remarks>
260
+ public ReadOnlyMemory < byte > ToMemoryUnsafe ( )
261
+ {
262
+ if ( _currentbuffer == null || _Length <= 0 )
263
+ {
264
+ return Memory < byte > . Empty ;
265
+ }
266
+ return _currentbuffer . AsMemory ( 0 , _Length ) ;
267
+ }
158
268
}
159
269
}
0 commit comments