From: Levi Broderick Date: Sat, 6 Oct 2018 14:58:51 +0000 (-0700) Subject: Move BinaryPrimitives into coreclr shared source (#20288) X-Git-Tag: accepted/tizen/unified/20190422.045933~1063 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6b412b2eab5c06499c66553beffbd3f3c12d3ed7;p=platform%2Fupstream%2Fcoreclr.git Move BinaryPrimitives into coreclr shared source (#20288) --- diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 6d6b9c2..ee2d2e6 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -54,6 +54,11 @@ + + + + + diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs b/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs new file mode 100644 index 0000000..ae3acdf --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs @@ -0,0 +1,126 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +namespace System.Buffers.Binary +{ + /// + /// Reads bytes as primitives with specific endianness + /// + /// + /// For native formats, MemoryExtensions.Read{T}; should be used. + /// Use these helpers when you need to read specific endinanness. + /// + public static partial class BinaryPrimitives + { + /// + /// This is a no-op and added only for consistency. + /// This allows the caller to read a struct of numeric primitives and reverse each field + /// rather than having to skip sbyte fields. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static sbyte ReverseEndianness(sbyte value) + { + return value; + } + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ReverseEndianness(short value) + { + return (short)((value & 0x00FF) << 8 | (value & 0xFF00) >> 8); + } + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReverseEndianness(int value) => (int)ReverseEndianness((uint)value); + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ReverseEndianness(long value) => (long)ReverseEndianness((ulong)value); + + /// + /// This is a no-op and added only for consistency. + /// This allows the caller to read a struct of numeric primitives and reverse each field + /// rather than having to skip byte fields. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte ReverseEndianness(byte value) + { + return value; + } + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ReverseEndianness(ushort value) + { + // Don't need to AND with 0xFF00 or 0x00FF since the final + // cast back to ushort will clear out all bits above [ 15 .. 00 ]. + // This is normally implemented via "movzx eax, ax" on the return. + // Alternatively, the compiler could elide the movzx instruction + // entirely if it knows the caller is only going to access "ax" + // instead of "eax" / "rax" when the function returns. + + return (ushort)((value >> 8) + (value << 8)); + } + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ReverseEndianness(uint value) + { + // This takes advantage of the fact that the JIT can detect + // ROL32 / ROR32 patterns and output the correct intrinsic. + // + // Input: value = [ ww xx yy zz ] + // + // First line generates : [ ww xx yy zz ] + // & [ 00 FF 00 FF ] + // = [ 00 xx 00 zz ] + // ROR32(8) = [ zz 00 xx 00 ] + // + // Second line generates: [ ww xx yy zz ] + // & [ FF 00 FF 00 ] + // = [ ww 00 yy 00 ] + // ROL32(8) = [ 00 yy 00 ww ] + // + // (sum) = [ zz yy xx ww ] + // + // Testing shows that throughput increases if the AND + // is performed before the ROL / ROR. + + uint mask_xx_zz = (value & 0x00FF00FFU); + uint mask_ww_yy = (value & 0xFF00FF00U); + return ((mask_xx_zz >> 8) | (mask_xx_zz << 24)) + + ((mask_ww_yy << 8) | (mask_ww_yy >> 24)); + } + + /// + /// Reverses a primitive value - performs an endianness swap + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ReverseEndianness(ulong value) + { + // Operations on 32-bit values have higher throughput than + // operations on 64-bit values, so decompose. + + return ((ulong)ReverseEndianness((uint)value) << 32) + + ReverseEndianness((uint)(value >> 32)); + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Binary/ReaderBigEndian.cs b/src/System.Private.CoreLib/shared/System/Buffers/Binary/ReaderBigEndian.cs new file mode 100644 index 0000000..b45dd89 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Buffers/Binary/ReaderBigEndian.cs @@ -0,0 +1,193 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Buffers.Binary +{ + public static partial class BinaryPrimitives + { + /// + /// Reads an Int16 out of a read-only span of bytes as big endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ReadInt16BigEndian(ReadOnlySpan source) + { + short result = MemoryMarshal.Read(source); + if (BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads an Int32 out of a read-only span of bytes as big endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadInt32BigEndian(ReadOnlySpan source) + { + int result = MemoryMarshal.Read(source); + if (BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads an Int64 out of a read-only span of bytes as big endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ReadInt64BigEndian(ReadOnlySpan source) + { + long result = MemoryMarshal.Read(source); + if (BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads a UInt16 out of a read-only span of bytes as big endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ReadUInt16BigEndian(ReadOnlySpan source) + { + ushort result = MemoryMarshal.Read(source); + if (BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads a UInt32 out of a read-only span of bytes as big endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ReadUInt32BigEndian(ReadOnlySpan source) + { + uint result = MemoryMarshal.Read(source); + if (BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads a UInt64 out of a read-only span of bytes as big endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ReadUInt64BigEndian(ReadOnlySpan source) + { + ulong result = MemoryMarshal.Read(source); + if (BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads an Int16 out of a read-only span of bytes as big endian. + /// If the span is too small to contain an Int16, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadInt16BigEndian(ReadOnlySpan source, out short value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads an Int32 out of a read-only span of bytes as big endian. + /// If the span is too small to contain an Int32, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadInt32BigEndian(ReadOnlySpan source, out int value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads an Int64 out of a read-only span of bytes as big endian. + /// If the span is too small to contain an Int64, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadInt64BigEndian(ReadOnlySpan source, out long value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads a UInt16 out of a read-only span of bytes as big endian. + /// If the span is too small to contain a UInt16, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadUInt16BigEndian(ReadOnlySpan source, out ushort value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads a UInt32 out of a read-only span of bytes as big endian. + /// If the span is too small to contain a UInt32, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadUInt32BigEndian(ReadOnlySpan source, out uint value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads a UInt64 out of a read-only span of bytes as big endian. + /// If the span is too small to contain a UInt64, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadUInt64BigEndian(ReadOnlySpan source, out ulong value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + } +} + diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Binary/ReaderLittleEndian.cs b/src/System.Private.CoreLib/shared/System/Buffers/Binary/ReaderLittleEndian.cs new file mode 100644 index 0000000..bd832f8 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Buffers/Binary/ReaderLittleEndian.cs @@ -0,0 +1,192 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Buffers.Binary +{ + public static partial class BinaryPrimitives + { + /// + /// Reads an Int16 out of a read-only span of bytes as little endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ReadInt16LittleEndian(ReadOnlySpan source) + { + short result = MemoryMarshal.Read(source); + if (!BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads an Int32 out of a read-only span of bytes as little endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadInt32LittleEndian(ReadOnlySpan source) + { + int result = MemoryMarshal.Read(source); + if (!BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads an Int64 out of a read-only span of bytes as little endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ReadInt64LittleEndian(ReadOnlySpan source) + { + long result = MemoryMarshal.Read(source); + if (!BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads a UInt16 out of a read-only span of bytes as little endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ReadUInt16LittleEndian(ReadOnlySpan source) + { + ushort result = MemoryMarshal.Read(source); + if (!BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads a UInt32 out of a read-only span of bytes as little endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ReadUInt32LittleEndian(ReadOnlySpan source) + { + uint result = MemoryMarshal.Read(source); + if (!BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads a UInt64 out of a read-only span of bytes as little endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ReadUInt64LittleEndian(ReadOnlySpan source) + { + ulong result = MemoryMarshal.Read(source); + if (!BitConverter.IsLittleEndian) + { + result = ReverseEndianness(result); + } + return result; + } + + /// + /// Reads an Int16 out of a read-only span of bytes as little endian. + /// If the span is too small to contain an Int16, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadInt16LittleEndian(ReadOnlySpan source, out short value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads an Int32 out of a read-only span of bytes as little endian. + /// If the span is too small to contain an Int32, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadInt32LittleEndian(ReadOnlySpan source, out int value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads an Int64 out of a read-only span of bytes as little endian. + /// If the span is too small to contain an Int64, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadInt64LittleEndian(ReadOnlySpan source, out long value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads a UInt16 out of a read-only span of bytes as little endian. + /// If the span is too small to contain a UInt16, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadUInt16LittleEndian(ReadOnlySpan source, out ushort value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads a UInt32 out of a read-only span of bytes as little endian. + /// If the span is too small to contain a UInt32, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadUInt32LittleEndian(ReadOnlySpan source, out uint value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + + /// + /// Reads a UInt64 out of a read-only span of bytes as little endian. + /// If the span is too small to contain a UInt64, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryReadUInt64LittleEndian(ReadOnlySpan source, out ulong value) + { + bool success = MemoryMarshal.TryRead(source, out value); + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return success; + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Binary/WriterBigEndian.cs b/src/System.Private.CoreLib/shared/System/Buffers/Binary/WriterBigEndian.cs new file mode 100644 index 0000000..78be9b5 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Buffers/Binary/WriterBigEndian.cs @@ -0,0 +1,180 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Buffers.Binary +{ + public static partial class BinaryPrimitives + { + /// + /// Writes an Int16 into a span of bytes as big endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteInt16BigEndian(Span destination, short value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Writes an Int32 into a span of bytes as big endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteInt32BigEndian(Span destination, int value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Writes an Int64 into a span of bytes as big endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteInt64BigEndian(Span destination, long value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Write a UInt16 into a span of bytes as big endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteUInt16BigEndian(Span destination, ushort value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Write a UInt32 into a span of bytes as big endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteUInt32BigEndian(Span destination, uint value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Write a UInt64 into a span of bytes as big endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteUInt64BigEndian(Span destination, ulong value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Writes an Int16 into a span of bytes as big endian. + /// If the span is too small to contain the value, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteInt16BigEndian(Span destination, short value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Writes an Int32 into a span of bytes as big endian. + /// If the span is too small to contain the value, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteInt32BigEndian(Span destination, int value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Writes an Int64 into a span of bytes as big endian. + /// If the span is too small to contain the value, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteInt64BigEndian(Span destination, long value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Write a UInt16 into a span of bytes as big endian. + /// If the span is too small to contain the value, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteUInt16BigEndian(Span destination, ushort value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Write a UInt32 into a span of bytes as big endian. + /// If the span is too small to contain the value, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteUInt32BigEndian(Span destination, uint value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Write a UInt64 into a span of bytes as big endian. + /// If the span is too small to contain the value, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteUInt64BigEndian(Span destination, ulong value) + { + if (BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Binary/WriterLittleEndian.cs b/src/System.Private.CoreLib/shared/System/Buffers/Binary/WriterLittleEndian.cs new file mode 100644 index 0000000..5d63ee5 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Buffers/Binary/WriterLittleEndian.cs @@ -0,0 +1,180 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Buffers.Binary +{ + public static partial class BinaryPrimitives + { + /// + /// Writes an Int16 into a span of bytes as little endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteInt16LittleEndian(Span destination, short value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Writes an Int32 into a span of bytes as little endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteInt32LittleEndian(Span destination, int value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Writes an Int64 into a span of bytes as little endian. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteInt64LittleEndian(Span destination, long value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Write a UInt16 into a span of bytes as little endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteUInt16LittleEndian(Span destination, ushort value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Write a UInt32 into a span of bytes as little endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteUInt32LittleEndian(Span destination, uint value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Write a UInt64 into a span of bytes as little endian. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteUInt64LittleEndian(Span destination, ulong value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + MemoryMarshal.Write(destination, ref value); + } + + /// + /// Writes an Int16 into a span of bytes as little endian. + /// If the span is too small to contain the value, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteInt16LittleEndian(Span destination, short value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Writes an Int32 into a span of bytes as little endian. + /// If the span is too small to contain the value, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteInt32LittleEndian(Span destination, int value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Writes an Int64 into a span of bytes as little endian. + /// If the span is too small to contain the value, return false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteInt64LittleEndian(Span destination, long value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Write a UInt16 into a span of bytes as little endian. + /// If the span is too small to contain the value, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteUInt16LittleEndian(Span destination, ushort value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Write a UInt32 into a span of bytes as little endian. + /// If the span is too small to contain the value, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteUInt32LittleEndian(Span destination, uint value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + + /// + /// Write a UInt64 into a span of bytes as little endian. + /// If the span is too small to contain the value, return false. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryWriteUInt64LittleEndian(Span destination, ulong value) + { + if (!BitConverter.IsLittleEndian) + { + value = ReverseEndianness(value); + } + return MemoryMarshal.TryWrite(destination, ref value); + } + } +}