Skip to content

Commit a0b6aa1

Browse files
authored
feat: Allow passing an allocator for FastBufferReader's internal handle when using Allocator.None [MTT-3534] (#1966)
1 parent c0c6b02 commit a0b6aa1

File tree

1 file changed

+52
-38
lines changed

1 file changed

+52
-38
lines changed

com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -54,25 +54,29 @@ internal unsafe void CommitBitwiseReads(int amount)
5454
#endif
5555
}
5656

57-
private static unsafe ReaderHandle* CreateHandle(byte* buffer, int length, int offset, Allocator allocator)
57+
private static unsafe ReaderHandle* CreateHandle(byte* buffer, int length, int offset, Allocator copyAllocator, Allocator internalAllocator)
5858
{
5959
ReaderHandle* readerHandle = null;
60-
if (allocator == Allocator.None)
60+
if (copyAllocator == Allocator.None)
6161
{
62-
readerHandle = (ReaderHandle*)UnsafeUtility.Malloc(sizeof(ReaderHandle) + length, UnsafeUtility.AlignOf<byte>(), Allocator.Temp);
62+
readerHandle = (ReaderHandle*)UnsafeUtility.Malloc(sizeof(ReaderHandle) + length, UnsafeUtility.AlignOf<byte>(), internalAllocator);
6363
readerHandle->BufferPointer = buffer;
6464
readerHandle->Position = offset;
6565
}
6666
else
6767
{
68-
readerHandle = (ReaderHandle*)UnsafeUtility.Malloc(sizeof(ReaderHandle) + length, UnsafeUtility.AlignOf<byte>(), allocator);
68+
readerHandle = (ReaderHandle*)UnsafeUtility.Malloc(sizeof(ReaderHandle) + length, UnsafeUtility.AlignOf<byte>(), copyAllocator);
6969
UnsafeUtility.MemCpy(readerHandle + 1, buffer + offset, length);
7070
readerHandle->BufferPointer = (byte*)(readerHandle + 1);
7171
readerHandle->Position = 0;
7272
}
7373

7474
readerHandle->Length = length;
75-
readerHandle->Allocator = allocator;
75+
76+
// If the copyAllocator provided is Allocator.None, there is a chance that the internalAllocator was provided
77+
// When we dispose, we are really only interested in disposing Allocator.Persistent and Allocator.TempJob
78+
// as disposing Allocator.Temp and Allocator.None would do nothing. Therefore, make sure we dispose the readerHandle with the right Allocator label
79+
readerHandle->Allocator = copyAllocator == Allocator.None ? internalAllocator : copyAllocator;
7680
#if DEVELOPMENT_BUILD || UNITY_EDITOR
7781
readerHandle->AllowedReadMark = 0;
7882
readerHandle->InBitwiseContext = false;
@@ -83,23 +87,26 @@ internal unsafe void CommitBitwiseReads(int amount)
8387
/// <summary>
8488
/// Create a FastBufferReader from a NativeArray.
8589
///
86-
/// A new buffer will be created using the given allocator and the value will be copied in.
90+
/// A new buffer will be created using the given <param name="copyAllocator"> and the value will be copied in.
8791
/// FastBufferReader will then own the data.
8892
///
89-
/// The exception to this is when the allocator passed in is Allocator.None. In this scenario,
93+
/// The exception to this is when the <param name="copyAllocator"> passed in is Allocator.None. In this scenario,
9094
/// ownership of the data remains with the caller and the reader will point at it directly.
9195
/// When created with Allocator.None, FastBufferReader will allocate some internal data using
92-
/// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive
96+
/// Allocator.Temp so it should be treated as if it's a ref struct and not allowed to outlive
9397
/// the context in which it was created (it should neither be returned from that function nor
94-
/// stored anywhere in heap memory).
98+
/// stored anywhere in heap memory). This is true, unless the <param name="internalAllocator"> param is explicitly set
99+
/// to i.e.: Allocator.Persistent in which case it would allow the internal data to Persist for longer, but the caller
100+
/// should manually call Dispose() when it is no longer needed.
95101
/// </summary>
96102
/// <param name="buffer"></param>
97-
/// <param name="allocator"></param>
103+
/// <param name="copyAllocator">The allocator type used for internal data when copying an existing buffer if other than Allocator.None is specified, that memory will be owned by this FastBufferReader instance</param>
98104
/// <param name="length"></param>
99105
/// <param name="offset"></param>
100-
public unsafe FastBufferReader(NativeArray<byte> buffer, Allocator allocator, int length = -1, int offset = 0)
106+
/// <param name="internalAllocator">The allocator type used for internal data when this reader points directly at a buffer owned by someone else</param>
107+
public unsafe FastBufferReader(NativeArray<byte> buffer, Allocator copyAllocator, int length = -1, int offset = 0, Allocator internalAllocator = Allocator.Temp)
101108
{
102-
Handle = CreateHandle((byte*)buffer.GetUnsafePtr(), length == -1 ? buffer.Length : length, offset, allocator);
109+
Handle = CreateHandle((byte*)buffer.GetUnsafePtr(), length == -1 ? buffer.Length : length, offset, copyAllocator, internalAllocator);
103110
}
104111

105112
/// <summary>
@@ -112,18 +119,18 @@ public unsafe FastBufferReader(NativeArray<byte> buffer, Allocator allocator, in
112119
/// and ensure the FastBufferReader isn't used outside that block.
113120
/// </summary>
114121
/// <param name="buffer">The buffer to copy from</param>
115-
/// <param name="allocator">The allocator to use</param>
122+
/// <param name="copyAllocator">The allocator type used for internal data when copying an existing buffer if other than Allocator.None is specified, that memory will be owned by this FastBufferReader instance</param>
116123
/// <param name="length">The number of bytes to copy (all if this is -1)</param>
117124
/// <param name="offset">The offset of the buffer to start copying from</param>
118-
public unsafe FastBufferReader(ArraySegment<byte> buffer, Allocator allocator, int length = -1, int offset = 0)
125+
public unsafe FastBufferReader(ArraySegment<byte> buffer, Allocator copyAllocator, int length = -1, int offset = 0)
119126
{
120-
if (allocator == Allocator.None)
127+
if (copyAllocator == Allocator.None)
121128
{
122129
throw new NotSupportedException("Allocator.None cannot be used with managed source buffers.");
123130
}
124131
fixed (byte* data = buffer.Array)
125132
{
126-
Handle = CreateHandle(data, length == -1 ? buffer.Count : length, offset, allocator);
133+
Handle = CreateHandle(data, length == -1 ? buffer.Count : length, offset, copyAllocator, Allocator.Temp);
127134
}
128135
}
129136

@@ -137,87 +144,94 @@ public unsafe FastBufferReader(ArraySegment<byte> buffer, Allocator allocator, i
137144
/// and ensure the FastBufferReader isn't used outside that block.
138145
/// </summary>
139146
/// <param name="buffer">The buffer to copy from</param>
140-
/// <param name="allocator">The allocator to use</param>
147+
/// <param name="copyAllocator">The allocator type used for internal data when copying an existing buffer if other than Allocator.None is specified, that memory will be owned by this FastBufferReader instance</param>
141148
/// <param name="length">The number of bytes to copy (all if this is -1)</param>
142149
/// <param name="offset">The offset of the buffer to start copying from</param>
143-
public unsafe FastBufferReader(byte[] buffer, Allocator allocator, int length = -1, int offset = 0)
150+
public unsafe FastBufferReader(byte[] buffer, Allocator copyAllocator, int length = -1, int offset = 0)
144151
{
145-
if (allocator == Allocator.None)
152+
if (copyAllocator == Allocator.None)
146153
{
147154
throw new NotSupportedException("Allocator.None cannot be used with managed source buffers.");
148155
}
149156
fixed (byte* data = buffer)
150157
{
151-
Handle = CreateHandle(data, length == -1 ? buffer.Length : length, offset, allocator);
158+
Handle = CreateHandle(data, length == -1 ? buffer.Length : length, offset, copyAllocator, Allocator.Temp);
152159
}
153160
}
154161

155162
/// <summary>
156163
/// Create a FastBufferReader from an existing byte buffer.
157164
///
158-
/// A new buffer will be created using the given allocator and the value will be copied in.
165+
/// A new buffer will be created using the given <param name="copyAllocator"> and the value will be copied in.
159166
/// FastBufferReader will then own the data.
160167
///
161-
/// The exception to this is when the allocator passed in is Allocator.None. In this scenario,
168+
/// The exception to this is when the <param name="copyAllocator"> passed in is Allocator.None. In this scenario,
162169
/// ownership of the data remains with the caller and the reader will point at it directly.
163170
/// When created with Allocator.None, FastBufferReader will allocate some internal data using
164171
/// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive
165172
/// the context in which it was created (it should neither be returned from that function nor
166-
/// stored anywhere in heap memory).
173+
/// stored anywhere in heap memory). This is true, unless the <param name="internalAllocator"> param is explicitly set
174+
/// to i.e.: Allocator.Persistent in which case it would allow the internal data to Persist for longer, but the caller
175+
/// should manually call Dispose() when it is no longer needed.
167176
/// </summary>
168177
/// <param name="buffer">The buffer to copy from</param>
169-
/// <param name="allocator">The allocator to use</param>
178+
/// <param name="copyAllocator">The allocator type used for internal data when copying an existing buffer if other than Allocator.None is specified, that memory will be owned by this FastBufferReader instance</param>
170179
/// <param name="length">The number of bytes to copy</param>
171180
/// <param name="offset">The offset of the buffer to start copying from</param>
172-
public unsafe FastBufferReader(byte* buffer, Allocator allocator, int length, int offset = 0)
181+
/// <param name="internalAllocator">The allocator type used for internal data when this reader points directly at a buffer owned by someone else</param>
182+
public unsafe FastBufferReader(byte* buffer, Allocator copyAllocator, int length, int offset = 0, Allocator internalAllocator = Allocator.Temp)
173183
{
174-
Handle = CreateHandle(buffer, length, offset, allocator);
184+
Handle = CreateHandle(buffer, length, offset, copyAllocator, internalAllocator);
175185
}
176186

177187
/// <summary>
178188
/// Create a FastBufferReader from a FastBufferWriter.
179189
///
180-
/// A new buffer will be created using the given allocator and the value will be copied in.
190+
/// A new buffer will be created using the given <param name="copyAllocator"> and the value will be copied in.
181191
/// FastBufferReader will then own the data.
182192
///
183-
/// The exception to this is when the allocator passed in is Allocator.None. In this scenario,
193+
/// The exception to this is when the <param name="copyAllocator"> passed in is Allocator.None. In this scenario,
184194
/// ownership of the data remains with the caller and the reader will point at it directly.
185195
/// When created with Allocator.None, FastBufferReader will allocate some internal data using
186196
/// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive
187197
/// the context in which it was created (it should neither be returned from that function nor
188-
/// stored anywhere in heap memory).
198+
/// stored anywhere in heap memory). This is true, unless the <param name="internalAllocator"> param is explicitly set
199+
/// to i.e.: Allocator.Persistent in which case it would allow the internal data to Persist for longer, but the caller
200+
/// should manually call Dispose() when it is no longer needed.
189201
/// </summary>
190202
/// <param name="writer">The writer to copy from</param>
191-
/// <param name="allocator">The allocator to use</param>
203+
/// <param name="copyAllocator">The allocator type used for internal data when copying an existing buffer if other than Allocator.None is specified, that memory will be owned by this FastBufferReader instance</param>
192204
/// <param name="length">The number of bytes to copy (all if this is -1)</param>
193205
/// <param name="offset">The offset of the buffer to start copying from</param>
194-
public unsafe FastBufferReader(FastBufferWriter writer, Allocator allocator, int length = -1, int offset = 0)
206+
/// <param name="internalAllocator">The allocator type used for internal data when this reader points directly at a buffer owned by someone else</param>
207+
public unsafe FastBufferReader(FastBufferWriter writer, Allocator copyAllocator, int length = -1, int offset = 0, Allocator internalAllocator = Allocator.Temp)
195208
{
196-
Handle = CreateHandle(writer.GetUnsafePtr(), length == -1 ? writer.Length : length, offset, allocator);
209+
Handle = CreateHandle(writer.GetUnsafePtr(), length == -1 ? writer.Length : length, offset, copyAllocator, internalAllocator);
197210
}
198211

199212
/// <summary>
200213
/// Create a FastBufferReader from another existing FastBufferReader. This is typically used when you
201-
/// want to change the allocator that a reader is allocated to - for example, upgrading a Temp reader to
214+
/// want to change the copyAllocator that a reader is allocated to - for example, upgrading a Temp reader to
202215
/// a Persistent one to be processed later.
203216
///
204-
/// A new buffer will be created using the given allocator and the value will be copied in.
217+
/// A new buffer will be created using the given <param name="copyAllocator"> and the value will be copied in.
205218
/// FastBufferReader will then own the data.
206219
///
207-
/// The exception to this is when the allocator passed in is Allocator.None. In this scenario,
220+
/// The exception to this is when the <param name="copyAllocator"> passed in is Allocator.None. In this scenario,
208221
/// ownership of the data remains with the caller and the reader will point at it directly.
209222
/// When created with Allocator.None, FastBufferReader will allocate some internal data using
210223
/// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive
211224
/// the context in which it was created (it should neither be returned from that function nor
212225
/// stored anywhere in heap memory).
213226
/// </summary>
214227
/// <param name="reader">The reader to copy from</param>
215-
/// <param name="allocator">The allocator to use</param>
228+
/// <param name="copyAllocator">The allocator type used for internal data when copying an existing buffer if other than Allocator.None is specified, that memory will be owned by this FastBufferReader instance</param>
216229
/// <param name="length">The number of bytes to copy (all if this is -1)</param>
217230
/// <param name="offset">The offset of the buffer to start copying from</param>
218-
public unsafe FastBufferReader(FastBufferReader reader, Allocator allocator, int length = -1, int offset = 0)
231+
/// <param name="internalAllocator">The allocator type used for internal data when this reader points directly at a buffer owned by someone else</param>
232+
public unsafe FastBufferReader(FastBufferReader reader, Allocator copyAllocator, int length = -1, int offset = 0, Allocator internalAllocator = Allocator.Temp)
219233
{
220-
Handle = CreateHandle(reader.GetUnsafePtr(), length == -1 ? reader.Length : length, offset, allocator);
234+
Handle = CreateHandle(reader.GetUnsafePtr(), length == -1 ? reader.Length : length, offset, copyAllocator, internalAllocator);
221235
}
222236

223237
/// <summary>

0 commit comments

Comments
 (0)