Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit 152af3d

Browse files
committed
CopyTo to Buffer.MemoryCopy
1 parent eadef6b commit 152af3d

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/MemoryPoolIterator.cs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -870,17 +870,30 @@ public int GetLength(MemoryPoolIterator end)
870870

871871
public MemoryPoolIterator CopyTo(byte[] array, int offset, int count, out int actual)
872872
{
873-
// Note: Ensure for any changes in this function Consume is changed to match
874873
if (count == 0 || IsDefault)
875874
{
876875
actual = 0;
877876
return this;
878877
}
878+
879879
if (array == null)
880880
{
881881
return Consume(count, out actual);
882882
}
883883

884+
Debug.Assert(count + offset <= array.Length);
885+
886+
#if NET451
887+
return BlockCopyTo(array, ref offset, count, out actual);
888+
#else
889+
return MemoryCopyTo(array, ref offset, count, out actual);
890+
#endif
891+
}
892+
893+
#if NET451
894+
private MemoryPoolIterator BlockCopyTo(byte[] array, ref int offset, int count, out int actual)
895+
{
896+
// Note: Ensure for any changes in this function MemoryCopyTo & Consume are changed to match
884897
var block = _block;
885898
var index = _index;
886899
var remaining = count;
@@ -914,9 +927,51 @@ public MemoryPoolIterator CopyTo(byte[] array, int offset, int count, out int ac
914927
}
915928
}
916929
}
930+
#else
931+
private unsafe MemoryPoolIterator MemoryCopyTo(byte[] array, ref int offset, int count, out int actual)
932+
{
933+
// Note: Ensure for any changes in this function BlockCopyTo & Consume are changed to match
934+
var block = _block;
935+
var index = _index;
936+
var remaining = count;
937+
fixed (byte* pArray = &array[0])
938+
{
939+
while (true)
940+
{
941+
// Determine if we might attempt to copy data from block.Next before
942+
// calculating "following" so we don't risk skipping data that could
943+
// be added after block.End when we decide to copy from block.Next.
944+
// block.End will always be advanced before block.Next is set.
945+
var wasLastBlock = block.Next == null;
946+
var following = block.End - index;
947+
if (remaining <= following)
948+
{
949+
actual = count;
950+
Buffer.MemoryCopy(block.DataFixedPtr + index, pArray + offset, remaining, remaining);
951+
return new MemoryPoolIterator(block, index + remaining);
952+
}
953+
else if (wasLastBlock)
954+
{
955+
actual = count - remaining + following;
956+
Buffer.MemoryCopy(block.DataFixedPtr + index, pArray + offset, following, following);
957+
return new MemoryPoolIterator(block, index + following);
958+
}
959+
else
960+
{
961+
Buffer.MemoryCopy(block.DataFixedPtr + index, pArray + offset, following, following);
962+
offset += following;
963+
remaining -= following;
964+
block = block.Next;
965+
index = block.Start;
966+
}
967+
}
968+
}
969+
}
970+
#endif
917971

918972
private MemoryPoolIterator Consume(int count, out int actual)
919973
{
974+
// Note: Ensure for any changes in this function CopyToBlockCopy & CopyToMemoryCopy are changed to match
920975
var block = _block;
921976
var index = _index;
922977
var remaining = count;

0 commit comments

Comments
 (0)