Skip to content

Commit 6f0093a

Browse files
author
deniaa
committed
Add interfaces and implementatoins with ReadonlySpan<byte> to IBinaryReader and IBinaryWriter
1 parent fac5628 commit 6f0093a

7 files changed

Lines changed: 126 additions & 2 deletions

File tree

Vostok.Commons.Binary.Tests/BinaryReadersWriters_Tests.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,18 @@ public void Should_correctly_write_and_read_byte_array_values(params byte[] valu
225225
Test(value, (item, writer) => writer.WriteWithoutLength(item), reader => reader.ReadByteArray(value.Length));
226226
}
227227

228+
229+
#if NET6_0_OR_GREATER
230+
[TestCase((byte)0xFF)]
231+
[TestCase((byte)0xFF, (byte)0xAB)]
232+
[TestCase((byte)0xC0, (byte)0xFF, (byte)0xEE, (byte)0xBA, (byte)0xBE)]
233+
public void Should_correctly_write_and_read_bytes_span_values(params byte[] value)
234+
{
235+
Test(value.AsSpan(), (item, writer) => writer.WriteWithLength(item), reader => reader.ReadBytesSpan());
236+
Test(value.AsSpan(), (item, writer) => writer.WriteWithoutLength(item), reader => reader.ReadBytesSpan(value.Length));
237+
}
238+
#endif
239+
228240
[Test]
229241
public void Should_correctly_write_and_read_timespan_values()
230242
{
@@ -312,7 +324,7 @@ public void Should_correctly_write_and_read_nullable_classes()
312324
reader => reader.ReadNullable(r => r.ReadString()));
313325
}
314326

315-
#region Helpers
327+
#region Helpers
316328

317329
private static void Test<T>(T item, Action<T, IBinaryWriter> write, Func<IBinaryReader, T> read)
318330
{
@@ -524,6 +536,6 @@ public override void Flush()
524536
=> throw new NotSupportedException();
525537
}
526538

527-
#endregion
539+
#endregion
528540
}
529541
}

Vostok.Commons.Binary/BinaryBufferReader.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,5 +306,33 @@ private void EnsureSufficientSizeRemaining(int size)
306306
if (size > BytesRemaining)
307307
throw new IndexOutOfRangeException($"Requested to read {size} bytes from buffer, but it only has {BytesRemaining} bytes remaining.");
308308
}
309+
310+
#if NET6_0_OR_GREATER
311+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
312+
public ReadOnlySpan<byte> ReadBytesSpan()
313+
{
314+
var size = ReadInt32();
315+
316+
EnsureSufficientSizeRemaining(size);
317+
318+
var result = new ReadOnlySpan<byte>(Buffer, (int)Position, size);
319+
320+
Position += size;
321+
322+
return result;
323+
}
324+
325+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
326+
public ReadOnlySpan<byte> ReadBytesSpan(int size)
327+
{
328+
EnsureSufficientSizeRemaining(size);
329+
330+
var result = new ReadOnlySpan<byte>(Buffer, (int)Position, size);
331+
332+
Position += size;
333+
334+
return result;
335+
}
336+
#endif
309337
}
310338
}

Vostok.Commons.Binary/BinaryBufferWriter.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,36 @@ public void WriteWithoutLength(byte[] value, int offset, int length)
347347
IncreaseLengthIfNeeded();
348348
}
349349

350+
#if NET6_0_OR_GREATER
351+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
352+
public void WriteWithLength(ReadOnlySpan<byte> value)
353+
{
354+
var length = value.Length;
355+
EnsureCapacity(length + sizeof(int));
356+
357+
Write(length);
358+
359+
value.CopyTo(new Span<byte>(Buffer, position, length));
360+
361+
position += length;
362+
363+
IncreaseLengthIfNeeded();
364+
}
365+
366+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
367+
public void WriteWithoutLength(ReadOnlySpan<byte> value)
368+
{
369+
var length = value.Length;
370+
EnsureCapacity(length);
371+
372+
value.CopyTo(new Span<byte>(Buffer, position, length));
373+
374+
position += length;
375+
376+
IncreaseLengthIfNeeded();
377+
}
378+
#endif
379+
350380
[MethodImpl(MethodImplOptions.AggressiveInlining)]
351381
public void Reset(int neededCapacity = 0)
352382
{

Vostok.Commons.Binary/BinaryStreamReader.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,18 @@ public byte[] ReadByteArray(int size)
164164
return result;
165165
}
166166

167+
#if NET6_0_OR_GREATER
168+
public ReadOnlySpan<byte> ReadBytesSpan()
169+
{
170+
return ReadByteArray().AsSpan();
171+
}
172+
173+
public ReadOnlySpan<byte> ReadBytesSpan(int size)
174+
{
175+
return ReadByteArray(size).AsSpan();
176+
}
177+
#endif
178+
167179
private void LoadIntoBufferExactly(int size)
168180
{
169181
ReadFromStreamExactly(buffer.Buffer, 0, size);

Vostok.Commons.Binary/BinaryStreamWriter.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,19 @@ public void WriteWithoutLength(byte[] value, int offset, int length)
194194
stream.Write(value, offset, length);
195195
}
196196

197+
#if NET6_0_OR_GREATER
198+
public void WriteWithLength(ReadOnlySpan<byte> value)
199+
{
200+
Write(value.Length);
201+
WriteWithoutLength(value);
202+
}
203+
204+
public void WriteWithoutLength(ReadOnlySpan<byte> value)
205+
{
206+
stream.Write(value);
207+
}
208+
#endif
209+
197210
[MethodImpl(MethodImplOptions.AggressiveInlining)]
198211
private void Flush()
199212
{

Vostok.Commons.Binary/IBinaryReader.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,20 @@ internal interface IBinaryReader
9696
/// </summary>
9797
[NotNull]
9898
byte[] ReadByteArray(int size);
99+
100+
#if NET6_0_OR_GREATER
101+
/// <summary>
102+
/// <para>Reads a span of bytes.</para>
103+
/// <para>Assumes that the value itself is prepended by its Int32 length.</para>
104+
/// <para>The resulting ReadOnlySpan may hold a reference to the source buffer if it exists. Be careful not to use this span after buffer and this reader released. Underlying buffer may be returned to pool and used under another reader. Or you can keep a huge buffer while this span is alive too.</para>
105+
/// </summary>
106+
ReadOnlySpan<byte> ReadBytesSpan();
107+
108+
/// <summary>
109+
/// <para>Reads a span of bytes of given <paramref name="size"/>.</para>
110+
/// <para>The resulting ReadOnlySpan may hold a reference to the source buffer if it exists. Be careful not to hold this span forever to avoid holding the source buffer.</para>
111+
/// </summary>
112+
ReadOnlySpan<byte> ReadBytesSpan(int size);
113+
#endif
99114
}
100115
}

Vostok.Commons.Binary/IBinaryWriter.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,19 @@ internal interface IBinaryWriter
105105
/// <para>The value itself is not automatically prepended with length (readers of binary result must know the length from external sources).</para>
106106
/// </summary>
107107
void WriteWithoutLength([NotNull] byte[] value, int offset, int length);
108+
109+
#if NET6_0_OR_GREATER
110+
/// <summary>
111+
/// <para>Writes given span of bytes as bytes array in its entirety.</para>
112+
/// <para>The value itself is automatically prepended with Int32 length (see <see cref="Write(int)"/>).</para>
113+
/// </summary>
114+
void WriteWithLength(ReadOnlySpan<byte> value);
115+
116+
/// <summary>
117+
/// <para>Writes given span of bytes as bytes array in its entirety.</para>
118+
/// <para>The value itself is not automatically prepended with length (readers of binary result must know the length from external sources).</para>
119+
/// </summary>
120+
void WriteWithoutLength(ReadOnlySpan<byte> value);
121+
#endif
108122
}
109123
}

0 commit comments

Comments
 (0)