Move BinaryPrimitives into coreclr shared source (#20288)
authorLevi Broderick <GrabYourPitchforks@users.noreply.github.com>
Sat, 6 Oct 2018 14:58:51 +0000 (07:58 -0700)
committerJan Kotas <jkotas@microsoft.com>
Sat, 6 Oct 2018 14:58:51 +0000 (07:58 -0700)
src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs [new file with mode: 0644]
src/System.Private.CoreLib/shared/System/Buffers/Binary/ReaderBigEndian.cs [new file with mode: 0644]
src/System.Private.CoreLib/shared/System/Buffers/Binary/ReaderLittleEndian.cs [new file with mode: 0644]
src/System.Private.CoreLib/shared/System/Buffers/Binary/WriterBigEndian.cs [new file with mode: 0644]
src/System.Private.CoreLib/shared/System/Buffers/Binary/WriterLittleEndian.cs [new file with mode: 0644]

index 6d6b9c2..ee2d2e6 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\MemoryManager.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\TlsOverPerCoreLockedStacksArrayPool.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Utilities.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\Reader.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\ReaderBigEndian.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\ReaderLittleEndian.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\WriterBigEndian.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\WriterLittleEndian.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\FormattingHelpers.CountDigits.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Byte.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Char.cs" />
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 (file)
index 0000000..ae3acdf
--- /dev/null
@@ -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
+{
+    /// <summary>
+    /// Reads bytes as primitives with specific endianness
+    /// </summary>
+    /// <remarks>
+    /// For native formats, MemoryExtensions.Read{T}; should be used.
+    /// Use these helpers when you need to read specific endinanness.
+    /// </remarks>
+    public static partial class BinaryPrimitives
+    {
+        /// <summary>
+        /// 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.
+        /// </summary> 
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static sbyte ReverseEndianness(sbyte value)
+        {
+            return value;
+        }
+
+        /// <summary>
+        /// Reverses a primitive value - performs an endianness swap
+        /// </summary> 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static short ReverseEndianness(short value)
+        {
+            return (short)((value & 0x00FF) << 8 | (value & 0xFF00) >> 8);
+        }
+
+        /// <summary>
+        /// Reverses a primitive value - performs an endianness swap
+        /// </summary> 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int ReverseEndianness(int value) => (int)ReverseEndianness((uint)value);
+
+        /// <summary>
+        /// Reverses a primitive value - performs an endianness swap
+        /// </summary> 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static long ReverseEndianness(long value) => (long)ReverseEndianness((ulong)value);
+
+        /// <summary>
+        /// 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.
+        /// </summary> 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static byte ReverseEndianness(byte value)
+        {
+            return value;
+        }
+
+        /// <summary>
+        /// Reverses a primitive value - performs an endianness swap
+        /// </summary> 
+        [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));
+        }
+
+        /// <summary>
+        /// Reverses a primitive value - performs an endianness swap
+        /// </summary> 
+        [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));
+        }
+
+        /// <summary>
+        /// Reverses a primitive value - performs an endianness swap
+        /// </summary> 
+        [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 (file)
index 0000000..b45dd89
--- /dev/null
@@ -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
+    {
+        /// <summary>
+        /// Reads an Int16 out of a read-only span of bytes as big endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static short ReadInt16BigEndian(ReadOnlySpan<byte> source)
+        {
+            short result = MemoryMarshal.Read<short>(source);
+            if (BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads an Int32 out of a read-only span of bytes as big endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int ReadInt32BigEndian(ReadOnlySpan<byte> source)
+        {
+            int result = MemoryMarshal.Read<int>(source);
+            if (BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads an Int64 out of a read-only span of bytes as big endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static long ReadInt64BigEndian(ReadOnlySpan<byte> source)
+        {
+            long result = MemoryMarshal.Read<long>(source);
+            if (BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads a UInt16 out of a read-only span of bytes as big endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static ushort ReadUInt16BigEndian(ReadOnlySpan<byte> source)
+        {
+            ushort result = MemoryMarshal.Read<ushort>(source);
+            if (BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads a UInt32 out of a read-only span of bytes as big endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static uint ReadUInt32BigEndian(ReadOnlySpan<byte> source)
+        {
+            uint result = MemoryMarshal.Read<uint>(source);
+            if (BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads a UInt64 out of a read-only span of bytes as big endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static ulong ReadUInt64BigEndian(ReadOnlySpan<byte> source)
+        {
+            ulong result = MemoryMarshal.Read<ulong>(source);
+            if (BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads an Int16 out of a read-only span of bytes as big endian.
+        /// <returns>If the span is too small to contain an Int16, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadInt16BigEndian(ReadOnlySpan<byte> source, out short value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads an Int32 out of a read-only span of bytes as big endian.
+        /// <returns>If the span is too small to contain an Int32, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadInt32BigEndian(ReadOnlySpan<byte> source, out int value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads an Int64 out of a read-only span of bytes as big endian.
+        /// <returns>If the span is too small to contain an Int64, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadInt64BigEndian(ReadOnlySpan<byte> source, out long value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads a UInt16 out of a read-only span of bytes as big endian.
+        /// <returns>If the span is too small to contain a UInt16, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadUInt16BigEndian(ReadOnlySpan<byte> source, out ushort value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads a UInt32 out of a read-only span of bytes as big endian.
+        /// <returns>If the span is too small to contain a UInt32, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadUInt32BigEndian(ReadOnlySpan<byte> source, out uint value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads a UInt64 out of a read-only span of bytes as big endian.
+        /// <returns>If the span is too small to contain a UInt64, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadUInt64BigEndian(ReadOnlySpan<byte> 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 (file)
index 0000000..bd832f8
--- /dev/null
@@ -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
+    {
+        /// <summary>
+        /// Reads an Int16 out of a read-only span of bytes as little endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static short ReadInt16LittleEndian(ReadOnlySpan<byte> source)
+        {
+            short result = MemoryMarshal.Read<short>(source);
+            if (!BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads an Int32 out of a read-only span of bytes as little endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int ReadInt32LittleEndian(ReadOnlySpan<byte> source)
+        {
+            int result = MemoryMarshal.Read<int>(source);
+            if (!BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads an Int64 out of a read-only span of bytes as little endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static long ReadInt64LittleEndian(ReadOnlySpan<byte> source)
+        {
+            long result = MemoryMarshal.Read<long>(source);
+            if (!BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads a UInt16 out of a read-only span of bytes as little endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static ushort ReadUInt16LittleEndian(ReadOnlySpan<byte> source)
+        {
+            ushort result = MemoryMarshal.Read<ushort>(source);
+            if (!BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads a UInt32 out of a read-only span of bytes as little endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static uint ReadUInt32LittleEndian(ReadOnlySpan<byte> source)
+        {
+            uint result = MemoryMarshal.Read<uint>(source);
+            if (!BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads a UInt64 out of a read-only span of bytes as little endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static ulong ReadUInt64LittleEndian(ReadOnlySpan<byte> source)
+        {
+            ulong result = MemoryMarshal.Read<ulong>(source);
+            if (!BitConverter.IsLittleEndian)
+            {
+                result = ReverseEndianness(result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Reads an Int16 out of a read-only span of bytes as little endian.
+        /// <returns>If the span is too small to contain an Int16, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadInt16LittleEndian(ReadOnlySpan<byte> source, out short value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads an Int32 out of a read-only span of bytes as little endian.
+        /// <returns>If the span is too small to contain an Int32, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadInt32LittleEndian(ReadOnlySpan<byte> source, out int value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads an Int64 out of a read-only span of bytes as little endian.
+        /// <returns>If the span is too small to contain an Int64, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadInt64LittleEndian(ReadOnlySpan<byte> source, out long value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads a UInt16 out of a read-only span of bytes as little endian.
+        /// <returns>If the span is too small to contain a UInt16, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadUInt16LittleEndian(ReadOnlySpan<byte> source, out ushort value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads a UInt32 out of a read-only span of bytes as little endian.
+        /// <returns>If the span is too small to contain a UInt32, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadUInt32LittleEndian(ReadOnlySpan<byte> source, out uint value)
+        {
+            bool success = MemoryMarshal.TryRead(source, out value);
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return success;
+        }
+
+        /// <summary>
+        /// Reads a UInt64 out of a read-only span of bytes as little endian.
+        /// <returns>If the span is too small to contain a UInt64, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryReadUInt64LittleEndian(ReadOnlySpan<byte> 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 (file)
index 0000000..78be9b5
--- /dev/null
@@ -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
+    {
+        /// <summary>
+        /// Writes an Int16 into a span of bytes as big endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteInt16BigEndian(Span<byte> destination, short value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int32 into a span of bytes as big endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteInt32BigEndian(Span<byte> destination, int value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int64 into a span of bytes as big endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteInt64BigEndian(Span<byte> destination, long value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt16 into a span of bytes as big endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteUInt16BigEndian(Span<byte> destination, ushort value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt32 into a span of bytes as big endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteUInt32BigEndian(Span<byte> destination, uint value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt64 into a span of bytes as big endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteUInt64BigEndian(Span<byte> destination, ulong value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int16 into a span of bytes as big endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteInt16BigEndian(Span<byte> destination, short value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int32 into a span of bytes as big endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteInt32BigEndian(Span<byte> destination, int value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int64 into a span of bytes as big endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteInt64BigEndian(Span<byte> destination, long value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt16 into a span of bytes as big endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteUInt16BigEndian(Span<byte> destination, ushort value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt32 into a span of bytes as big endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteUInt32BigEndian(Span<byte> destination, uint value)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt64 into a span of bytes as big endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteUInt64BigEndian(Span<byte> 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 (file)
index 0000000..5d63ee5
--- /dev/null
@@ -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
+    {
+        /// <summary>
+        /// Writes an Int16 into a span of bytes as little endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteInt16LittleEndian(Span<byte> destination, short value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int32 into a span of bytes as little endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteInt32LittleEndian(Span<byte> destination, int value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int64 into a span of bytes as little endian.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteInt64LittleEndian(Span<byte> destination, long value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt16 into a span of bytes as little endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteUInt16LittleEndian(Span<byte> destination, ushort value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt32 into a span of bytes as little endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteUInt32LittleEndian(Span<byte> destination, uint value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt64 into a span of bytes as little endian.
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void WriteUInt64LittleEndian(Span<byte> destination, ulong value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            MemoryMarshal.Write(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int16 into a span of bytes as little endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteInt16LittleEndian(Span<byte> destination, short value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int32 into a span of bytes as little endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteInt32LittleEndian(Span<byte> destination, int value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Writes an Int64 into a span of bytes as little endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteInt64LittleEndian(Span<byte> destination, long value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt16 into a span of bytes as little endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteUInt16LittleEndian(Span<byte> destination, ushort value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt32 into a span of bytes as little endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteUInt32LittleEndian(Span<byte> destination, uint value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+
+        /// <summary>
+        /// Write a UInt64 into a span of bytes as little endian.
+        /// <returns>If the span is too small to contain the value, return false.</returns>
+        /// </summary>
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool TryWriteUInt64LittleEndian(Span<byte> destination, ulong value)
+        {
+            if (!BitConverter.IsLittleEndian)
+            {
+                value = ReverseEndianness(value);
+            }
+            return MemoryMarshal.TryWrite(destination, ref value);
+        }
+    }
+}