// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace System.Buffers.Binary { public static partial class BinaryPrimitives { /// <summary> /// Writes a <see cref="double" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 8 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="double" />. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteDoubleBigEndian(Span<byte> destination, double value) { if (BitConverter.IsLittleEndian) { long tmp = ReverseEndianness(BitConverter.DoubleToInt64Bits(value)); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="Half" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 2 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="Half" />. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteHalfBigEndian(Span<byte> destination, Half value) { if (BitConverter.IsLittleEndian) { short tmp = ReverseEndianness(BitConverter.HalfToInt16Bits(value)); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="BFloat16" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 2 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="BFloat16" />. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteBFloat16BigEndian(Span<byte> destination, BFloat16 value) { if (BitConverter.IsLittleEndian) { short tmp = ReverseEndianness(BitConverter.BFloat16ToInt16Bits(value)); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="short" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 2 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="short" />. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteInt16BigEndian(Span<byte> destination, short value) { if (BitConverter.IsLittleEndian) { short tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="int" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 4 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="int" />. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteInt32BigEndian(Span<byte> destination, int value) { if (BitConverter.IsLittleEndian) { int tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="long" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 8 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="long" />. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteInt64BigEndian(Span<byte> destination, long value) { if (BitConverter.IsLittleEndian) { long tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="Int128" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 16 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="Int128" />. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteInt128BigEndian(Span<byte> destination, Int128 value) { if (BitConverter.IsLittleEndian) { Int128 tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="nint" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 4 bytes on 32-bit platforms -or- 8 bytes on 64-bit platforms to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="nint" />. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteIntPtrBigEndian(Span<byte> destination, nint value) { if (BitConverter.IsLittleEndian) { nint tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="float" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 4 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="float" />. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteSingleBigEndian(Span<byte> destination, float value) { if (BitConverter.IsLittleEndian) { int tmp = ReverseEndianness(BitConverter.SingleToInt32Bits(value)); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Write a <see cref="ushort" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 2 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="ushort" />. /// </exception> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteUInt16BigEndian(Span<byte> destination, ushort value) { if (BitConverter.IsLittleEndian) { ushort tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Write a <see cref="uint" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 4 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="uint" />. /// </exception> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteUInt32BigEndian(Span<byte> destination, uint value) { if (BitConverter.IsLittleEndian) { uint tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Write a <see cref="ulong" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 8 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="ulong" />. /// </exception> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteUInt64BigEndian(Span<byte> destination, ulong value) { if (BitConverter.IsLittleEndian) { ulong tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="UInt128" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 16 bytes to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="UInt128" />. /// </exception> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteUInt128BigEndian(Span<byte> destination, UInt128 value) { if (BitConverter.IsLittleEndian) { UInt128 tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="nuint" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <remarks>Writes exactly 4 bytes on 32-bit platforms -or- 8 bytes on 64-bit platforms to the beginning of the span.</remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="destination" /> is too small to contain a <see cref="nuint" />. /// </exception> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteUIntPtrBigEndian(Span<byte> destination, nuint value) { if (BitConverter.IsLittleEndian) { nuint tmp = ReverseEndianness(value); MemoryMarshal.Write(destination, in tmp); } else { MemoryMarshal.Write(destination, in value); } } /// <summary> /// Writes a <see cref="double" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="double" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 8 bytes to the beginning of the span.</remarks> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteDoubleBigEndian(Span<byte> destination, double value) { if (BitConverter.IsLittleEndian) { long tmp = ReverseEndianness(BitConverter.DoubleToInt64Bits(value)); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="Half" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="Half" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 2 bytes to the beginning of the span.</remarks> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteHalfBigEndian(Span<byte> destination, Half value) { if (BitConverter.IsLittleEndian) { short tmp = ReverseEndianness(BitConverter.HalfToInt16Bits(value)); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="BFloat16" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="BFloat16" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 2 bytes to the beginning of the span.</remarks> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteBFloat16BigEndian(Span<byte> destination, BFloat16 value) { if (BitConverter.IsLittleEndian) { short tmp = ReverseEndianness(BitConverter.BFloat16ToInt16Bits(value)); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="short" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="short" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 2 bytes to the beginning of the span.</remarks> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteInt16BigEndian(Span<byte> destination, short value) { if (BitConverter.IsLittleEndian) { short tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="int" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="int" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 4 bytes to the beginning of the span.</remarks> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteInt32BigEndian(Span<byte> destination, int value) { if (BitConverter.IsLittleEndian) { int tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="long" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="long" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 8 bytes to the beginning of the span.</remarks> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteInt64BigEndian(Span<byte> destination, long value) { if (BitConverter.IsLittleEndian) { long tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="Int128" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="Int128" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 16 bytes to the beginning of the span.</remarks> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteInt128BigEndian(Span<byte> destination, Int128 value) { if (BitConverter.IsLittleEndian) { Int128 tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="nint" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="nint" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 4 bytes on 32-bit platforms -or- 8 bytes on 64-bit platforms to the beginning of the span.</remarks> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteIntPtrBigEndian(Span<byte> destination, nint value) { if (BitConverter.IsLittleEndian) { nint tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="float" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="float" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 4 bytes to the beginning of the span.</remarks> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteSingleBigEndian(Span<byte> destination, float value) { if (BitConverter.IsLittleEndian) { int tmp = ReverseEndianness(BitConverter.SingleToInt32Bits(value)); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Write a <see cref="ushort" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="ushort" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 2 bytes to the beginning of the span.</remarks> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteUInt16BigEndian(Span<byte> destination, ushort value) { if (BitConverter.IsLittleEndian) { ushort tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Write a <see cref="uint" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="uint" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 4 bytes to the beginning of the span.</remarks> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteUInt32BigEndian(Span<byte> destination, uint value) { if (BitConverter.IsLittleEndian) { uint tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Write a <see cref="ulong" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="ulong" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 8 bytes to the beginning of the span.</remarks> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteUInt64BigEndian(Span<byte> destination, ulong value) { if (BitConverter.IsLittleEndian) { ulong tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="UInt128" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="UInt128" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 16 bytes to the beginning of the span.</remarks> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteUInt128BigEndian(Span<byte> destination, UInt128 value) { if (BitConverter.IsLittleEndian) { UInt128 tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } /// <summary> /// Writes a <see cref="nuint" /> into a span of bytes, as big endian. /// </summary> /// <param name="destination">The span of bytes where the value is to be written, as big endian.</param> /// <param name="value">The value to write into the span of bytes.</param> /// <returns> /// <see langword="true" /> if the span is large enough to contain a <see cref="nuint" />; otherwise, <see langword="false" />. /// </returns> /// <remarks>Writes exactly 4 bytes on 32-bit platforms -or- 8 bytes on 64-bit platforms to the beginning of the span.</remarks> [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWriteUIntPtrBigEndian(Span<byte> destination, nuint value) { if (BitConverter.IsLittleEndian) { nuint tmp = ReverseEndianness(value); return MemoryMarshal.TryWrite(destination, in tmp); } return MemoryMarshal.TryWrite(destination, in value); } } } |