Commit 83178a43 authored by Ray Koopa's avatar Ray Koopa

Implement primitives.

parent 35770a69
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;
}
}
}
using System;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
using System.Text;
namespace Syroot.BinaryData.Memory
{
/// <summary>
/// Represents a position in a <see cref="ReadOnlySpan{Byte}"/> at which data is read from.
/// </summary>
public ref struct SpanReader
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
private ByteConverter _byteConverter;
private Encoding _encoding;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="SpanReader"/> struct to operate on the given
/// <paramref name="span"/>.
/// </summary>
/// <param name="span">The <see cref="ReadOnlySpan{Byte}"/> to read from.</param>
/// <param name="byteConverter">The <see cref="ByteConverter"/> to use. Defaults to
/// <see cref="ByteConverter.System"/>.</param>
/// <param name="encoding">The character encoding to use. Defaults to <see cref="Encoding.UTF8"/>.</param>
public SpanReader(ReadOnlySpan<byte> span, ByteConverter byteConverter = null, Encoding encoding = null)
{
Span = span;
Position = 0;
_byteConverter = byteConverter ?? ByteConverter.System;
_encoding = encoding ?? Encoding.UTF8;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the <see cref="ByteConverter"/> instance used to parse multibyte binary data with.
/// Setting this value to <c>null</c> will restore the default <see cref="ByteConverter.System"/>.
/// </summary>
public ByteConverter ByteConverter
{
get => _byteConverter;
set => _byteConverter = value ?? ByteConverter.System;
}
/// <summary>
/// Gets or sets the encoding used for string related operations where no other encoding has been provided.
/// Setting this value to <c>null</c> will restore the default <see cref="Encoding.UTF8"/>.
/// </summary>
public Encoding Encoding
{
get => _encoding;
set => _encoding = value ?? Encoding.UTF8;
}
/// <summary>
/// Gets a value indicating whether the current position reached the end of the span.
/// </summary>
public bool IsEndOfSpan => Span.Length - Position <= 0;
/// <summary>
/// Gets the length of the underlying <see cref="Span"/>.
/// </summary>
public int Length => Span.Length;
/// <summary>
/// Gets the <see cref="ReadOnlySpan{Byte}"/> from which data is read.
/// </summary>
public ReadOnlySpan<byte> Span { get; }
/// <summary>
/// Gets or sets the position at which the next data is read from.
/// </summary>
public int Position { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Aligns the position 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 int Align(int alignment) => Position += Algebra.GetAlignmentDelta(Position, alignment);
/// <summary>
/// Reads the given number of <see cref="Byte"/> values from the current position.
/// </summary>
/// <returns>The value retrieved from the current position.</returns>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
public Byte[] ReadBytes(int count)
{
byte[] value = Span.Slice(Position, count).ToArray();
Position += count;
return value;
}
/// <summary>
/// Reads a <see cref="Byte"/> value from the current position.
/// </summary>
/// <returns>The value retrieved from the current position.</returns>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
public Byte ReadByte() => Span[Position++];
/// <summary>
/// Reads an <see cref="Int16"/> value from the current position.
/// </summary>
/// <returns>The value retrieved from the current position.</returns>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
public Int16 ReadInt16()
{
Int16 value = MemoryMarshal.Read<Int16>(Span.Slice(Position));
Position += sizeof(Int16);
return _byteConverter == ByteConverter.System ? value : BinaryPrimitives.ReverseEndianness(value);
}
/// <summary>
/// Reads an <see cref="Int32"/> value from the current position.
/// </summary>
/// <returns>The value retrieved from the current position.</returns>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
public Int32 ReadInt32()
{
Int32 value = MemoryMarshal.Read<Int32>(Span.Slice(Position));
Position += sizeof(Int32);
return _byteConverter == ByteConverter.System ? value : BinaryPrimitives.ReverseEndianness(value);
}
/// <summary>
/// Reads an <see cref="Int64"/> value from the current position.
/// </summary>
/// <returns>The value retrieved from the current position.</returns>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
public Int64 ReadInt64()
{
Int64 value = MemoryMarshal.Read<Int64>(Span.Slice(Position));
Position += sizeof(Int64);
return _byteConverter == ByteConverter.System ? value : BinaryPrimitives.ReverseEndianness(value);
}
/// <summary>
/// Reads an <see cref="SByte"/> value from the current position.
/// </summary>
/// <returns>The value retrieved from the current position.</returns>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
public SByte ReadSByte() => (SByte)Span[Position++];
/// <summary>
/// Reads a <see cref="UInt16"/> value from the current position.
/// </summary>
/// <returns>The value retrieved from the current position.</returns>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
public UInt16 ReadUInt16()
{
UInt16 value = MemoryMarshal.Read<UInt16>(Span.Slice(Position));
Position += sizeof(UInt16);
return _byteConverter == ByteConverter.System ? value : BinaryPrimitives.ReverseEndianness(value);
}
/// <summary>
/// Reads a <see cref="UInt32"/> value from the current position.
/// </summary>
/// <returns>The value retrieved from the current position.</returns>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
public UInt32 ReadUInt32()
{
UInt32 value = MemoryMarshal.Read<UInt32>(Span.Slice(Position));
Position += sizeof(UInt32);
return _byteConverter == ByteConverter.System ? value : BinaryPrimitives.ReverseEndianness(value);
}
/// <summary>
/// Reads a <see cref="UInt64"/> value from the current position.
/// </summary>
/// <returns>The value retrieved from the current position.</returns>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
public UInt64 ReadUInt64()
{
UInt64 value = MemoryMarshal.Read<UInt64>(Span.Slice(Position));
Position += sizeof(UInt64);
return ByteConverter == ByteConverter.System ? value : BinaryPrimitives.ReverseEndianness(value);
}
/// <summary>
/// Gets a <see cref="SpanReader"/> for the remaining data following the current position.
/// </summary>
/// <returns>The <see cref="SpanReader"/> covering the remaining data.</returns>
public SpanReader Slice() => new SpanReader(Span.Slice(Position));
/// <summary>
/// Gets a <see cref="SpanReader"/> for the data covered from the given <paramref name="start"/> position.
/// </summary>
/// <param name="start">The position from which to start covering data.</param>
/// <returns>The <see cref="SpanReader"/> covering the remaining data.</returns>
public SpanReader Slice(int start) => new SpanReader(Span.Slice(start));
/// <summary>
/// Gets a <see cref="SpanReader"/> for the data covered by the given <paramref name="start"/> position and
/// <paramref name="length"/>.
/// </summary>
/// <param name="start">The position from which to start covering data.</param>
/// <param name="length">The number of bytes to cover.</param>
/// <returns>The <see cref="SpanReader"/> covering the remaining data.</returns>
public SpanReader Slice(int start, int length) => new SpanReader(Span.Slice(start, length));
}
}
This diff is collapsed.
......@@ -13,9 +13,10 @@
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://gitlab.com/Syroot/BinaryData</RepositoryUrl>
<TargetFrameworks>net452;netstandard2.0</TargetFrameworks>
<VersionPrefix>5.1.0-beta1</VersionPrefix>
<VersionPrefix>5.1.0-alpha1</VersionPrefix>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.2" />
<PackageReference Include="System.Memory" Version="4.5.2" />
<ProjectReference Include="..\Syroot.BinaryData\Syroot.BinaryData.csproj" />
</ItemGroup>
</Project>
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