Skip to content

Commit 2902f17

Browse files
committed
Optimized: MemoryStream to not Allocate Heap Memory when Not Needed
1 parent 0ac92f6 commit 2902f17

2 files changed

Lines changed: 71 additions & 14 deletions

File tree

Source/Reloaded.Memory/Streams/ExtendedMemoryStream.cs

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
using System.IO;
1+
using System;
2+
using System.IO;
23
using System.Runtime.CompilerServices;
4+
using System.Runtime.InteropServices;
35

46
namespace Reloaded.Memory.Streams
57
{
68
/// <summary>
79
/// An extended version of the <see cref="MemoryStream"/> class that allows you to directly add generic structs to the stream.
810
/// </summary>
9-
public partial class ExtendedMemoryStream : MemoryStream
11+
public unsafe partial class ExtendedMemoryStream : MemoryStream
1012
{
13+
private const int MaxStackLimit = 1024;
14+
1115
/// <inheritdoc />
1216
public ExtendedMemoryStream() { }
1317

@@ -61,25 +65,78 @@ public void AddPadding(byte value, int alignment = 2048)
6165
/// Appends an unmanaged structure onto the <see cref="MemoryStream"/> and advances the position.
6266
/// </summary>
6367
[MethodImpl(MethodImplOptions.AggressiveInlining)]
64-
public void Write<T>(T[] structure) where T : unmanaged => Write(StructArray.GetBytes(structure));
68+
public void Write<T>(T[] structure) where T : unmanaged
69+
{
70+
for (int x = 0; x < structure.Length; x++)
71+
Write(ref structure[x]);
72+
}
6573

6674
/// <summary>
6775
/// Appends an managed/marshalled structure onto the <see cref="MemoryStream"/> and advances the position.
6876
/// </summary>
6977
[MethodImpl(MethodImplOptions.AggressiveInlining)]
70-
public void Write<T>(T[] structure, bool marshalStructure = true) => Write(StructArray.GetBytes(structure, marshalStructure));
78+
public void Write<T>(T[] structure, bool marshalStructure = true)
79+
{
80+
for (int x = 0; x < structure.Length; x++)
81+
Write(ref structure[x], marshalStructure);
82+
}
7183

7284
/// <summary>
7385
/// Appends an unmanaged structure onto the <see cref="MemoryStream"/> and advances the position.
7486
/// </summary>
7587
[MethodImpl(MethodImplOptions.AggressiveInlining)]
76-
public void Write<T>(T structure) where T : unmanaged => Write(Struct.GetBytes(structure));
88+
public void Write<T>(T structure) where T : unmanaged => Write(ref structure);
89+
90+
/// <summary>
91+
/// Appends an unmanaged structure onto the <see cref="MemoryStream"/> and advances the position.
92+
/// </summary>
93+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
94+
public void Write<T>(ref T structure) where T : unmanaged
95+
{
96+
#if FEATURE_NATIVE_SPAN
97+
if (sizeof(T) < MaxStackLimit)
98+
{
99+
Span<byte> stack = stackalloc byte[sizeof(T)];
100+
Struct.GetBytes(ref structure, stack);
101+
base.Write(stack);
102+
}
103+
else
104+
{
105+
Write(Struct.GetBytes(structure));
106+
}
107+
#else
108+
Write(Struct.GetBytes(structure));
109+
#endif
110+
}
111+
112+
/// <summary>
113+
/// Appends a managed/marshalled structure onto the given <see cref="MemoryStream"/> and advances the position.
114+
/// </summary>
115+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
116+
public void Write<T>(T structure, bool marshalStructure = true) => Write(ref structure, marshalStructure);
77117

78118
/// <summary>
79119
/// Appends a managed/marshalled structure onto the given <see cref="MemoryStream"/> and advances the position.
80120
/// </summary>
81121
[MethodImpl(MethodImplOptions.AggressiveInlining)]
82-
public void Write<T>(T structure, bool marshalStructure = true) => Write(Struct.GetBytes(structure, marshalStructure));
122+
public void Write<T>(ref T structure, bool marshalStructure = true)
123+
{
124+
#if FEATURE_NATIVE_SPAN
125+
var size = Struct.GetSize<T>(true);
126+
if (size < MaxStackLimit)
127+
{
128+
Span<byte> stack = stackalloc byte[size];
129+
Struct.GetBytes(ref structure, marshalStructure, stack);
130+
base.Write(stack);
131+
}
132+
else
133+
{
134+
Write(Struct.GetBytes(structure, marshalStructure));
135+
}
136+
#else
137+
Write(Struct.GetBytes(structure, marshalStructure));
138+
#endif
139+
}
83140

84141
/// <summary>
85142
/// Appends bytes onto the given <see cref="MemoryStream"/> and advances the position.
@@ -92,8 +149,8 @@ public void AddPadding(byte value, int alignment = 2048)
92149
[MethodImpl(MethodImplOptions.AggressiveInlining)]
93150
public void WriteBigEndianPrimitive<T>(T[] structures) where T : unmanaged
94151
{
95-
foreach (var structure in structures)
96-
WriteBigEndianPrimitive(structure);
152+
for (var x = 0; x < structures.Length; x++)
153+
WriteBigEndianPrimitive(structures[x]);
97154
}
98155

99156
/// <summary>
@@ -102,8 +159,8 @@ public void WriteBigEndianPrimitive<T>(T[] structures) where T : unmanaged
102159
[MethodImpl(MethodImplOptions.AggressiveInlining)]
103160
public void WriteBigEndianStruct<T>(T[] structures) where T : unmanaged, IEndianReversible
104161
{
105-
foreach (var structure in structures)
106-
WriteBigEndianStruct(structure);
162+
for (var x = 0; x < structures.Length; x++)
163+
WriteBigEndianStruct(structures[x]);
107164
}
108165

109166
/// <summary>
@@ -113,7 +170,7 @@ public void WriteBigEndianStruct<T>(T[] structures) where T : unmanaged, IEndian
113170
public void WriteBigEndianPrimitive<T>(T structure) where T : unmanaged
114171
{
115172
Endian.Reverse(ref structure);
116-
Write(Struct.GetBytes(structure));
173+
Write(ref structure);
117174
}
118175

119176
/// <summary>
@@ -123,7 +180,7 @@ public void WriteBigEndianPrimitive<T>(T structure) where T : unmanaged
123180
public void WriteBigEndianStruct<T>(T structure) where T : unmanaged, IEndianReversible
124181
{
125182
structure.SwapEndian();
126-
Write(Struct.GetBytes(structure));
183+
Write(ref structure);
127184
}
128185

129186
private static int RoundUp(int number, int multiple)

Source/Reloaded.Memory/Streams/Writers/LittleEndianMemoryStream.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public LittleEndianMemoryStream(ExtendedMemoryStream stream) : base(stream) { }
1919
public override void Write<T>(T[] structure) => Stream.Write(structure);
2020

2121
/// <inheritdoc />
22-
public override void Write<T>(T structure) => Stream.Write(structure);
22+
public override void Write<T>(T structure) => Stream.Write(ref structure);
2323

2424
/// <summary>
2525
/// Appends an managed/marshalled structure onto the <see cref="MemoryStream"/> and advances the position.
@@ -31,6 +31,6 @@ public LittleEndianMemoryStream(ExtendedMemoryStream stream) : base(stream) { }
3131
/// Appends a managed/marshalled structure onto the given <see cref="MemoryStream"/> and advances the position.
3232
/// </summary>
3333
[MethodImpl(MethodImplOptions.AggressiveInlining)]
34-
public void Write<T>(T structure, bool marshalStructure = true) => Stream.Write(structure, marshalStructure);
34+
public void Write<T>(T structure, bool marshalStructure = true) => Stream.Write(ref structure, marshalStructure);
3535
}
3636
}

0 commit comments

Comments
 (0)