From 5b6ca9c1603140db9eb913eb9f2aa1d7cb5ffbc7 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 29 Oct 2019 00:08:23 -0500 Subject: [PATCH] Add BlitStruct and BlitSpan --- src/LibHac/Common/BlitSpan.cs | 102 ++++++++++++++++++++++++++++++++ src/LibHac/Common/BlitStruct.cs | 68 +++++++++++++-------- src/LibHac/ThrowHelper.cs | 5 ++ 3 files changed, 150 insertions(+), 25 deletions(-) create mode 100644 src/LibHac/Common/BlitSpan.cs diff --git a/src/LibHac/Common/BlitSpan.cs b/src/LibHac/Common/BlitSpan.cs new file mode 100644 index 00000000..78940967 --- /dev/null +++ b/src/LibHac/Common/BlitSpan.cs @@ -0,0 +1,102 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace LibHac.Common +{ + /// + /// Provides a representation of a region of memory as if it were a series of blittable structs + /// of type . Also allows viewing the memory as a of bytes. + /// + /// The element type. + public ref struct BlitSpan where T : unmanaged + { + private readonly Span _buffer; + + /// + /// The number of elements of type in the . + /// + public int Length => _buffer.Length; + + /// + /// A reference to the first element in this collection. + /// + public ref T Value => ref _buffer[0]; + + /// + /// A reference to the element at index . + /// + public ref T this[int index] => ref _buffer[index]; + + /// + /// Creates a new using the provided . + /// + /// The span from which to create the . + /// Must have a length of at least 1. + public BlitSpan(Span data) + { + if (data.Length == 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + _buffer = data; + } + + /// + /// Creates a new using the provided of bytes. + /// + /// The byte span from which to create the . + /// Must be long enough to hold at least one struct of type + public BlitSpan(Span data) + { + if (data.Length < Unsafe.SizeOf()) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + _buffer = MemoryMarshal.Cast(data); + } + + /// + /// Creates a new over a struct of type . + /// + /// The struct from which to create the . + public BlitSpan(ref T data) + { + _buffer = SpanHelpers.AsSpan(ref data); + } + + /// + /// A of the elements in the . + /// + public Span Span => _buffer; + + /// + /// Returns a view of the as a of bytes. + /// + /// A byte span representation of the . + public Span GetByteSpan() + { + return MemoryMarshal.Cast(_buffer); + } + + /// + /// Returns a view of the element at index as a of bytes. + /// + /// The zero-based index of the element. + /// A byte span representation of the element. + public Span GetByteSpan(int elementIndex) + { + Span element = _buffer.Slice(elementIndex, 1); + return MemoryMarshal.Cast(element); + } + + /// + /// Calculates the length of memory in bytes that would be needed to store + /// elements of type . + /// + /// The number of elements. + /// The number of bytes required. + public static int QueryByteLength(int elementCount) + { + return Unsafe.SizeOf() * elementCount; + } + } +} diff --git a/src/LibHac/Common/BlitStruct.cs b/src/LibHac/Common/BlitStruct.cs index 70e4dad8..e2c6540c 100644 --- a/src/LibHac/Common/BlitStruct.cs +++ b/src/LibHac/Common/BlitStruct.cs @@ -5,45 +5,63 @@ using System.Runtime.InteropServices; namespace LibHac.Common { - public ref struct BlitStruct where T : unmanaged + /// + /// Handles storing a blittable struct or a series of blittable structs in a byte array. + /// + /// The element type. + public readonly struct BlitStruct where T : unmanaged { - private readonly Span _buffer; + private readonly byte[] _buffer; - public int Length => _buffer.Length; + public int Length => _buffer.Length / Unsafe.SizeOf(); - public ref T Value => ref _buffer[0]; - public ref T this[int index] => ref _buffer[index]; - - public BlitStruct(Span data) + /// + /// A reference to the first element in this collection. + /// + public ref T Value { - _buffer = data; + get + { + Debug.Assert(_buffer.Length >= Unsafe.SizeOf()); - Debug.Assert(_buffer.Length != 0); + return ref Unsafe.As(ref _buffer[0]); + } } - public BlitStruct(Span data) + /// + /// Initializes a new that can hold the specified number + /// of elements of type . + /// + /// The number of elements the will be able to store. + public BlitStruct(int elementCount) { - _buffer = MemoryMarshal.Cast(data); + if (elementCount <= 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); - Debug.Assert(_buffer.Length != 0); + _buffer = new byte[QueryByteLength(elementCount)]; } - public BlitStruct(ref T data) - { - _buffer = SpanHelpers.AsSpan(ref data); - } + /// + /// Returns a view of the elements in the current as type . + /// + public Span Span => MemoryMarshal.Cast(_buffer); - public Span GetByteSpan() - { - return MemoryMarshal.Cast(_buffer); - } + /// + /// Returns a view of the elements in the current as s. + /// + public Span ByteSpan => _buffer; - public Span GetByteSpan(int elementIndex) - { - Span element = _buffer.Slice(elementIndex, 1); - return MemoryMarshal.Cast(element); - } + /// + /// Creates a from the current . + /// + public BlitSpan BlitSpan => new BlitSpan(_buffer); + /// + /// Calculates the length of memory in bytes that would be needed to store + /// elements of type . + /// + /// The number of elements. + /// The number of bytes required. public static int QueryByteLength(int elementCount) { return Unsafe.SizeOf() * elementCount; diff --git a/src/LibHac/ThrowHelper.cs b/src/LibHac/ThrowHelper.cs index c13fa3e9..2eb6773d 100644 --- a/src/LibHac/ThrowHelper.cs +++ b/src/LibHac/ThrowHelper.cs @@ -14,5 +14,10 @@ namespace LibHac public static void ThrowResult(Result result, string message, Exception innerException) => throw new HorizonResultException(result, message, innerException); + + internal static void ThrowArgumentOutOfRangeException() + { + throw new ArgumentOutOfRangeException(); + } } }