Skip to content

Commit df64f76

Browse files
committed
Reduces allocations
1 parent 23a62b2 commit df64f76

File tree

1 file changed

+34
-7
lines changed

1 file changed

+34
-7
lines changed

src/MemoryStreamUtil.cs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,42 @@ private static byte[] GetBytesFromMemoryStream(System.IO.MemoryStream memStream)
197197
return result;
198198
}
199199

200-
// Fallback (position-aware)
201-
byte[] all = memStream.ToArray();
200+
// Fallback (position-aware) without copying the entire stream (MemoryStream.ToArray()).
201+
// Preserve caller's Position semantics.
202+
long originalPos = memStream.CanSeek ? memStream.Position : 0;
203+
byte[] resultFallback = GC.AllocateUninitializedArray<byte>(remaining);
202204

203-
if (pos64 == 0 && all.Length == remaining)
204-
return all;
205+
try
206+
{
207+
if (memStream.CanSeek)
208+
memStream.Position = pos64;
205209

206-
byte[] slice = GC.AllocateUninitializedArray<byte>(remaining);
207-
Buffer.BlockCopy(all, (int)pos64, slice, 0, remaining);
208-
return slice;
210+
var totalRead = 0;
211+
212+
while (totalRead < remaining)
213+
{
214+
int read = memStream.Read(resultFallback, totalRead, remaining - totalRead);
215+
if (read == 0)
216+
break;
217+
totalRead += read;
218+
}
219+
220+
if (totalRead != remaining)
221+
{
222+
// Extremely defensive: if stream length changed mid-read (shouldn't happen for MemoryStream),
223+
// return the bytes we did read.
224+
byte[] truncated = new byte[totalRead];
225+
Buffer.BlockCopy(resultFallback, 0, truncated, 0, totalRead);
226+
return truncated;
227+
}
228+
229+
return resultFallback;
230+
}
231+
finally
232+
{
233+
if (memStream.CanSeek)
234+
memStream.Position = originalPos;
235+
}
209236
}
210237

211238
private async ValueTask<byte[]> GetBytesFromNonMemoryStream(Stream stream, CancellationToken cancellationToken)

0 commit comments

Comments
 (0)