Commit 42d47b9c authored by Ray Koopa's avatar Ray Koopa

Add experimental Memory package focusing new span functionality.

parent 6639782f
namespace Syroot.BinaryData.Memory
{
/// <summary>
/// Represents mathemtical helper functions.
/// </summary>
internal static class Algebra
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Calculates the delta required to add to <paramref name="position"/> to reach the given
/// <paramref name="alignment"/>.
/// </summary>
/// <param name="position">The initial position.</param>
/// <param name="alignment">The multiple to align to. If negative, the delta is negative to reach the previous
/// multiple rather than the next one.</param>
/// <returns>The delta to add to the position.</returns>
internal static int GetAlignmentDelta(int position, int alignment)
{
return (-position % alignment + alignment) % alignment;
}
}
}
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Syroot.BinaryData.Memory
{
/// <summary>
/// Represents a position into a <see cref="ReadOnlySpan{Byte}"/> of which data can be read from.
/// </summary>
public ref struct ReadOnlySpanCursor
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
/// <summary>The <see cref="ReadOnlySpan{Byte}"/> of which data is read from.</summary>
public ReadOnlySpan<byte> Span;
/// <summary>The position at which the next data is read from.</summary>
public int Position;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlySpanCursor"/> struct to operate on the given
/// <paramref name="span"/>.
/// </summary>
/// <param name="span">The <see cref="Span{Byte}"/> to read from.</param>
public ReadOnlySpanCursor(ReadOnlySpan<byte> span)
{
Span = span;
Position = 0;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets a value indicating whether the cursor reached the end of the span.
/// </summary>
public bool EndOfSpan => Span.Length - Position <= 0;
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Gets a <see cref="ReadOnlySpan{Byte}"/> covering the remaining data following the cursor.
/// </summary>
/// <returns>The <see cref="ReadOnlySpan{Byte}"/> covering the remaining data.</returns>
public ReadOnlySpan<byte> SliceRemainder() => Span.Slice(Position, Span.Length - Position);
/// <summary>
/// Reads a structure of type <typeparamref name="T"/> from the current position.
/// </summary>
/// <typeparam name="T">The type of the structure.</typeparam>
/// <returns>The structure retrieved from the current position.</returns>
/// <exception cref="ArgumentException"><typeparamref name="T"/> contains references or pointers.</exception>
/// <exception cref="ArgumentOutOfRangeException">The number of remaining bytes available are less than
/// <typeparamref name="T"/> would require.</exception>
/// <remarks>
/// <typeparamref name="T"/> cannot contain pointers or references. It is checked at runtime in order to
/// preserve type safety.
/// </remarks>
public T Read<T>()
where T : struct
{
T value = MemoryMarshal.Read<T>(Span.Slice(Position));
Position += Unsafe.SizeOf<T>();
return value;
}
/// <summary>
/// Tries to read a structure of type <typeparamref name="T"/> from the current position.
/// </summary>
/// <typeparam name="T">The type of the structure.</typeparam>
/// <param name="value">When the method returns, an instance of <typeparamref name="T"/>.</param>
/// <returns><see langword="true"/> if the method succeeds in retrieving and instance of the structure;
/// otherwise, <see langword="false"/>.</returns>
/// <exception cref="ArgumentException"><typeparamref name="T"/> contains references or pointers.</exception>
/// <remarks>
/// <typeparamref name="T"/> cannot contain pointers or references. It is checked at runtime in order to
/// preserve type safety.
/// </remarks>
public bool TryRead<T>(out T value)
where T : struct
{
if (MemoryMarshal.TryRead(Span.Slice(Position), out value))
{
Position += Unsafe.SizeOf<T>();
return true;
}
return false;
}
}
}
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Syroot.BinaryData.Memory
{
/// <summary>
/// Represents a position into a <see cref="Span{Byte}"/> of which data can be read from or written to.
/// </summary>
public ref struct SpanCursor
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
/// <summary>The <see cref="Span{Byte}"/> of which data is read from or written to.</summary>
public Span<byte> Span;
/// <summary>The position at which the next data is read from or written to.</summary>
public int Position;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="SpanCursor"/> struct to operate on the given
/// <paramref name="span"/>.
/// </summary>
/// <param name="span">The <see cref="Span{Byte}"/> to read from or write to.</param>
public SpanCursor(Span<byte> span)
{
Span = span;
Position = 0;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets a value indicating whether the cursor reached the end of the span.
/// </summary>
public bool IsEndOfSpan => Span.Length - Position <= 0;
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Aligns the cursor to the given byte multiple.
/// </summary>
/// <param name="alignment">The byte multiple to align to. If negative, the position is decreased to the
/// previous multiple rather than the next one.</param>
/// <returns>The new position.</returns>
public void Align(int alignment)
{
Position += Algebra.GetAlignmentDelta(Position, alignment);
}
/// <summary>
/// Gets a <see cref="Span{Byte}"/> covering the remaining data following the cursor.
/// </summary>
/// <returns>The <see cref="Span{Byte}"/> covering the remaining data.</returns>
public Span<byte> SliceRemainder() => Span.Slice(Position, Span.Length - Position);
/// <summary>
/// Reads a structure of type <typeparamref name="T"/> from the current position.
/// </summary>
/// <typeparam name="T">The type of the structure.</typeparam>
/// <returns>The structure retrieved from the current position.</returns>
/// <exception cref="ArgumentException"><typeparamref name="T"/> contains references or pointers.</exception>
/// <exception cref="ArgumentOutOfRangeException">The number of remaining bytes available are less than
/// <typeparamref name="T"/> would require.</exception>
/// <remarks>
/// <typeparamref name="T"/> cannot contain pointers or references. It is checked at runtime in order to
/// preserve type safety.
/// </remarks>
public T Read<T>()
where T : struct
{
T value = MemoryMarshal.Read<T>(Span.Slice(Position));
Position += Unsafe.SizeOf<T>();
return value;
}
/// <summary>
/// Tries to read a structure of type <typeparamref name="T"/> from the current position.
/// </summary>
/// <typeparam name="T">The type of the structure.</typeparam>
/// <param name="value">When the method returns, an instance of <typeparamref name="T"/>.</param>
/// <returns><see langword="true"/> if the method succeeds in retrieving and instance of the structure;
/// otherwise, <see langword="false"/>.</returns>
/// <exception cref="ArgumentException"><typeparamref name="T"/> contains references or pointers.</exception>
/// <remarks>
/// <typeparamref name="T"/> cannot contain pointers or references. It is checked at runtime in order to
/// preserve type safety.
/// </remarks>
public bool TryRead<T>(out T value)
where T : struct
{
if (MemoryMarshal.TryRead(Span.Slice(Position), out value))
{
Position += Unsafe.SizeOf<T>();
return true;
}
return false;
}
/// <summary>
/// Write a structure of type <typeparamref name="T"/> into a span of bytes.
/// </summary>
/// <typeparam name="T">The type of the structure.</typeparam>
/// <param name="value">The structure to be written at the current position.</param>
/// <exception cref="ArgumentException"><typeparamref name="T"/> contains references or pointers.</exception>
/// <exception cref="ArgumentOutOfRangeException">The number of remaining bytes available are less than
/// <typeparamref name="T"/> would require.</exception>
/// <remarks>
/// <typeparamref name="T"/> cannot contain pointers or references. It is checked at runtime in order to
/// preserve type safety.
/// </remarks>
public void Write<T>(ref T value)
where T : struct
{
MemoryMarshal.Write(Span.Slice(Position), ref value);
Position += Unsafe.SizeOf<T>();
}
/// <summary>
/// Tries to write a structure of type <typeparamref name="T"/> into a span of bytes.
/// </summary>
/// <typeparam name="T">The type of the structure.</typeparam>
/// <param name="value">The structure to be written at the current position.</param>
/// <returns><see langword="true"/> if the method succeeds in writing the instance of the structure;
/// otherwise, <see langword="false"/>.</returns>
/// <exception cref="ArgumentException"><typeparamref name="T"/> contains references or pointers.</exception>
/// <remarks>
/// <typeparamref name="T"/> cannot contain pointers or references. It is checked at runtime in order to
/// preserve type safety.
/// </remarks>
public bool TryWrite<T>(ref T value)
where T : struct
{
if (MemoryMarshal.TryWrite(Span.Slice(Position), ref value))
{
Position += Unsafe.SizeOf<T>();
return true;
}
return false;
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Authors>Syroot</Authors>
<Copyright>(c) Syroot, licensed under MIT</Copyright>
<Description>.NET library extending span data reading and writing functionality.</Description>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<LangVersion>latest</LangVersion>
<PackageIconUrl>https://gitlab.com/Syroot/BinaryData/raw/master/res/icon.png</PackageIconUrl>
<PackageLicenseUrl>https://gitlab.com/Syroot/BinaryData/raw/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://gitlab.com/Syroot/BinaryData</PackageProjectUrl>
<PackageReleaseNotes>Initial release.</PackageReleaseNotes>
<PackageTags>binary data memory span readonlymemory readonlyspan</PackageTags>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://gitlab.com/Syroot/BinaryData</RepositoryUrl>
<TargetFrameworks>net452;netstandard2.0</TargetFrameworks>
<VersionPrefix>5.1.0-beta1</VersionPrefix>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.2" />
</ItemGroup>
</Project>
......@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.BinaryData.Serializa
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.BinaryData.Serialization.UnitTest", "Syroot.BinaryData.Serialization.UnitTest\Syroot.BinaryData.Serialization.UnitTest.csproj", "{CBB0637C-986F-4399-8689-F4F22027D973}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.BinaryData.Memory", "Syroot.BinaryData.Memory\Syroot.BinaryData.Memory.csproj", "{C618C9FE-F8AD-40D0-8E7C-608FB938B821}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
......@@ -42,6 +44,12 @@ Global
{CBB0637C-986F-4399-8689-F4F22027D973}.Release|Any CPU.Build.0 = Release|Any CPU
{CBB0637C-986F-4399-8689-F4F22027D973}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU
{CBB0637C-986F-4399-8689-F4F22027D973}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU
{C618C9FE-F8AD-40D0-8E7C-608FB938B821}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C618C9FE-F8AD-40D0-8E7C-608FB938B821}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C618C9FE-F8AD-40D0-8E7C-608FB938B821}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C618C9FE-F8AD-40D0-8E7C-608FB938B821}.Release|Any CPU.Build.0 = Release|Any CPU
{C618C9FE-F8AD-40D0-8E7C-608FB938B821}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU
{C618C9FE-F8AD-40D0-8E7C-608FB938B821}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment