From 7de0d403d534b7aca680f1ac0c77788710d61f03 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 4 Nov 2022 04:57:47 -0400 Subject: [PATCH] Add BinaryPrimitives.ReverseEndianness for spans of elements (#76339) --- src/libraries/System.Memory/ref/System.Memory.cs | 21 ++ .../tests/Binary/ReverseEndiannessUnitTests.cs | 134 ++++++++++++ .../src/System.Private.CoreLib.Shared.projitems | 1 + .../Binary/BinaryPrimitives.ReverseEndianness.cs | 228 +++++++++++++++++++++ .../src/System/Buffers/Binary/Reader.cs | 35 ++-- 5 files changed, 403 insertions(+), 16 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReverseEndianness.cs diff --git a/src/libraries/System.Memory/ref/System.Memory.cs b/src/libraries/System.Memory/ref/System.Memory.cs index 9836bb6..9e0c91d 100644 --- a/src/libraries/System.Memory/ref/System.Memory.cs +++ b/src/libraries/System.Memory/ref/System.Memory.cs @@ -442,6 +442,27 @@ namespace System.Buffers.Binary public static uint ReverseEndianness(uint value) { throw null; } [System.CLSCompliantAttribute(false)] public static ulong ReverseEndianness(ulong value) { throw null; } + public static nint ReverseEndianness(nint value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static nuint ReverseEndianness(nuint value) { throw null; } + public static System.Int128 ReverseEndianness(System.Int128 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.UInt128 ReverseEndianness(System.UInt128 value) { throw null; } + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } + [System.CLSCompliant(false)] + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } + [System.CLSCompliant(false)] + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } + [System.CLSCompliant(false)] + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } + [System.CLSCompliant(false)] + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } + [System.CLSCompliant(false)] + public static void ReverseEndianness(System.ReadOnlySpan source, System.Span destination) { } public static bool TryReadDoubleBigEndian(System.ReadOnlySpan source, out double value) { throw null; } public static bool TryReadDoubleLittleEndian(System.ReadOnlySpan source, out double value) { throw null; } public static bool TryReadHalfBigEndian(System.ReadOnlySpan source, out System.Half value) { throw null; } diff --git a/src/libraries/System.Memory/tests/Binary/ReverseEndiannessUnitTests.cs b/src/libraries/System.Memory/tests/Binary/ReverseEndiannessUnitTests.cs index 733059b..fce420e 100644 --- a/src/libraries/System.Memory/tests/Binary/ReverseEndiannessUnitTests.cs +++ b/src/libraries/System.Memory/tests/Binary/ReverseEndiannessUnitTests.cs @@ -1,6 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Runtime.InteropServices; using Xunit; namespace System.Buffers.Binary.Tests @@ -41,6 +45,13 @@ namespace System.Buffers.Binary.Tests Assert.Equal((int)a, BinaryPrimitives.ReverseEndianness((int)b)); Assert.Equal(b, BinaryPrimitives.ReverseEndianness(a)); Assert.Equal(a, BinaryPrimitives.ReverseEndianness(b)); + if (IntPtr.Size == 4) + { + Assert.Equal((nint)b, BinaryPrimitives.ReverseEndianness((nint)a)); + Assert.Equal((nint)a, BinaryPrimitives.ReverseEndianness((nint)b)); + Assert.Equal((nuint)b, BinaryPrimitives.ReverseEndianness((nuint)a)); + Assert.Equal((nuint)a, BinaryPrimitives.ReverseEndianness((nuint)b)); + } } [Theory] @@ -52,6 +63,129 @@ namespace System.Buffers.Binary.Tests Assert.Equal((long)a, BinaryPrimitives.ReverseEndianness((long)b)); Assert.Equal(b, BinaryPrimitives.ReverseEndianness(a)); Assert.Equal(a, BinaryPrimitives.ReverseEndianness(b)); + if (IntPtr.Size == 8) + { + Assert.Equal((nint)b, BinaryPrimitives.ReverseEndianness((nint)a)); + Assert.Equal((nint)a, BinaryPrimitives.ReverseEndianness((nint)b)); + Assert.Equal((nuint)b, BinaryPrimitives.ReverseEndianness((nuint)a)); + Assert.Equal((nuint)a, BinaryPrimitives.ReverseEndianness((nuint)b)); + } + } + + [Theory] + [InlineData(0x0123456789ABCDEF, 0xABCDEF0123456789)] + public void ReverseEndianness_Int128AndUInt128(ulong aLower, ulong aUpper) + { + Int128 original = new Int128(aLower, aUpper); + Int128 reversed = new Int128(BinaryPrimitives.ReverseEndianness(aUpper), BinaryPrimitives.ReverseEndianness(aLower)); + + Assert.Equal(reversed, BinaryPrimitives.ReverseEndianness(original)); + Assert.Equal((UInt128)reversed, BinaryPrimitives.ReverseEndianness((UInt128)original)); + } + + public static IEnumerable ReverseEndianness_Span_MemberData() + { + var r = new Random(42); + foreach (int length in Enumerable.Range(0, 36)) + { + yield return new object[] { Enumerable.Range(0, length).Select(_ => (ushort)r.Next(int.MinValue, int.MaxValue)).ToArray() }; + yield return new object[] { Enumerable.Range(0, length).Select(_ => (short)r.Next(int.MinValue, int.MaxValue)).ToArray() }; + yield return new object[] { Enumerable.Range(0, length).Select(_ => (uint)r.Next(int.MinValue, int.MaxValue)).ToArray() }; + yield return new object[] { Enumerable.Range(0, length).Select(_ => r.Next(int.MinValue, int.MaxValue)).ToArray() }; + yield return new object[] { Enumerable.Range(0, length).Select(_ => (ulong)r.NextInt64(long.MinValue, long.MaxValue)).ToArray() }; + yield return new object[] { Enumerable.Range(0, length).Select(_ => r.NextInt64(long.MinValue, long.MaxValue)).ToArray() }; + yield return new object[] { Enumerable.Range(0, length).Select(_ => (nuint)r.NextInt64(long.MinValue, long.MaxValue)).ToArray() }; + yield return new object[] { Enumerable.Range(0, length).Select(_ => (nint)r.NextInt64(long.MinValue, long.MaxValue)).ToArray() }; + yield return new object[] { Enumerable.Range(0, length).Select(_ => new UInt128((ulong)r.NextInt64(long.MinValue, long.MaxValue), (ulong)r.NextInt64(long.MinValue, long.MaxValue))).ToArray() }; + yield return new object[] { Enumerable.Range(0, length).Select(_ => new Int128((ulong)r.NextInt64(long.MinValue, long.MaxValue), (ulong)r.NextInt64(long.MinValue, long.MaxValue))).ToArray() }; + } + } + + [Theory] + [MemberData(nameof(ReverseEndianness_Span_MemberData))] + public void ReverseEndianness_Span_AllElementsReversed(T[] original) where T : struct, INumber + { + T[] expected = original.Select(ReverseEndianness).ToArray(); + T[] originalCopy = (T[])original.Clone(); + + T[] actual1 = (T[])original.Clone(); + T[] actual2 = new T[original.Length]; + T[] actual3 = new T[original.Length + 1]; + + // In-place + ReverseEndianness(actual1, actual1); + Assert.Equal(expected, actual1); + + // Different destination + ReverseEndianness(original, actual2); + Assert.Equal(originalCopy, original); + Assert.Equal(expected, actual2); + + // Different larger destination + ReverseEndianness(original, actual3); + Assert.Equal(originalCopy, original); + Assert.Equal(expected, actual3[0..^1]); + Assert.Equal(default, actual3[^1]); + + foreach (int offset in new[] { 1, 2, 3 }) + { + if (original.Length > offset) + { + // In-place shifted +offset + expected = original.AsSpan(0, original.Length - offset).ToArray().Select(ReverseEndianness).ToArray(); + actual1 = (T[])original.Clone(); + ReverseEndianness(actual1.AsSpan(0, actual1.Length - offset), actual1.AsSpan(offset)); + Assert.Equal(expected, actual1.AsSpan(offset).ToArray()); + for (int i = 0; i < offset; i++) + { + Assert.Equal(original[i], actual1[i]); + } + + // In-place shifted -offset + expected = original.AsSpan(offset).ToArray().Select(ReverseEndianness).ToArray(); + actual2 = (T[])original.Clone(); + ReverseEndianness(actual2.AsSpan(offset), actual2.AsSpan(0, actual2.Length - offset)); + Assert.Equal(expected, actual2.AsSpan(0, actual2.Length - offset).ToArray()); + Assert.Equal(original[^offset], actual2[^offset]); + } + } + + // Throws if the destination is too short + if (original.Length > 0) + { + T[] destination = new T[original.Length - 1]; + AssertExtensions.Throws("destination", () => ReverseEndianness(original, destination)); + } + } + + private static T ReverseEndianness(T value) + { + if (typeof(T) == typeof(ushort)) return (T)(object)BinaryPrimitives.ReverseEndianness((ushort)(object)value); + if (typeof(T) == typeof(short)) return (T)(object)BinaryPrimitives.ReverseEndianness((short)(object)value); + if (typeof(T) == typeof(uint)) return (T)(object)BinaryPrimitives.ReverseEndianness((uint)(object)value); + if (typeof(T) == typeof(int)) return (T)(object)BinaryPrimitives.ReverseEndianness((int)(object)value); + if (typeof(T) == typeof(ulong)) return (T)(object)BinaryPrimitives.ReverseEndianness((ulong)(object)value); + if (typeof(T) == typeof(long)) return (T)(object)BinaryPrimitives.ReverseEndianness((long)(object)value); + if (typeof(T) == typeof(nuint)) return (T)(object)BinaryPrimitives.ReverseEndianness((nuint)(object)value); + if (typeof(T) == typeof(nint)) return (T)(object)BinaryPrimitives.ReverseEndianness((nint)(object)value); + if (typeof(T) == typeof(UInt128)) return (T)(object)BinaryPrimitives.ReverseEndianness((UInt128)(object)value); + if (typeof(T) == typeof(Int128)) return (T)(object)BinaryPrimitives.ReverseEndianness((Int128)(object)value); + throw new Exception($"Unexpected type {typeof(T)}"); + } + + private static void ReverseEndianness(ReadOnlySpan source, Span destination) where T : struct + { + if (typeof(T) == typeof(ushort)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + if (typeof(T) == typeof(short)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + if (typeof(T) == typeof(uint)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + if (typeof(T) == typeof(int)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + if (typeof(T) == typeof(ulong)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + if (typeof(T) == typeof(long)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + if (typeof(T) == typeof(nuint)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + if (typeof(T) == typeof(nint)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + if (typeof(T) == typeof(UInt128)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + if (typeof(T) == typeof(Int128)) { BinaryPrimitives.ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); return; } + throw new Exception($"Unexpected type {typeof(T)}"); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 1b81686..ad70614 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -103,6 +103,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReverseEndianness.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReverseEndianness.cs new file mode 100644 index 0000000..6f355d2 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/BinaryPrimitives.ReverseEndianness.cs @@ -0,0 +1,228 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace System.Buffers.Binary +{ + public static partial class BinaryPrimitives + { + /// Copies every primitive value from to , reversing each primitive by performing an endianness swap as part of writing each. + /// The source span to copy. + /// The destination to which the source elements should be copied. + /// The source and destination spans may overlap. The same span may be passed as both the source and the destination in order to reverse each element's endianness in place. + /// The 's length is smaller than that of the . + [CLSCompliant(false)] + public static void ReverseEndianness(ReadOnlySpan source, Span destination) => + ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); + + /// + public static void ReverseEndianness(ReadOnlySpan source, Span destination) => + ReverseEndianness(source, destination); + + /// + [CLSCompliant(false)] + public static void ReverseEndianness(ReadOnlySpan source, Span destination) => + ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); + + /// + public static void ReverseEndianness(ReadOnlySpan source, Span destination) => + ReverseEndianness(source, destination); + + /// + [CLSCompliant(false)] + public static void ReverseEndianness(ReadOnlySpan source, Span destination) => + ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); + + /// + public static void ReverseEndianness(ReadOnlySpan source, Span destination) => + ReverseEndianness(source, destination); + + /// + [CLSCompliant(false)] + public static void ReverseEndianness(ReadOnlySpan source, Span destination) => +#if TARGET_64BIT + ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); +#else + ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); +#endif + + /// + public static void ReverseEndianness(ReadOnlySpan source, Span destination) => +#if TARGET_64BIT + ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); +#else + ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); +#endif + + private readonly struct Int16EndiannessReverser : IEndiannessReverser + { + public static short Reverse(short value) => + ReverseEndianness(value); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Reverse(Vector128 vector) => + Vector128.ShiftLeft(vector, 8) | Vector128.ShiftRightLogical(vector, 8); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Reverse(Vector256 vector) => + Vector256.ShiftLeft(vector, 8) | Vector256.ShiftRightLogical(vector, 8); + } + + private readonly struct Int32EndiannessReverser : IEndiannessReverser + { + public static int Reverse(int value) => + ReverseEndianness(value); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Reverse(Vector128 vector) => + Vector128.Shuffle(vector.AsByte(), Vector128.Create((byte)3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12)).AsInt32(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Reverse(Vector256 vector) => + Vector256.Shuffle(vector.AsByte(), Vector256.Create((byte)3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 19, 18, 17, 16, 23, 22, 21, 20, 27, 26, 25, 24, 31, 30, 29, 28)).AsInt32(); + } + + private readonly struct Int64EndiannessReverser : IEndiannessReverser + { + public static long Reverse(long value) => + ReverseEndianness(value); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Reverse(Vector128 vector) => + Vector128.Shuffle(vector.AsByte(), Vector128.Create((byte)7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8)).AsInt64(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Reverse(Vector256 vector) => + Vector256.Shuffle(vector.AsByte(), Vector256.Create((byte)7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24)).AsInt64(); + } + + private static void ReverseEndianness(ReadOnlySpan source, Span destination) + where T : struct + where TReverser : IEndiannessReverser + { + if (destination.Length < source.Length) + { + ThrowDestinationTooSmall(); + } + + ref T sourceRef = ref MemoryMarshal.GetReference(source); + ref T destRef = ref MemoryMarshal.GetReference(destination); + + if (Unsafe.AreSame(ref sourceRef, ref destRef) || + !source.Overlaps(destination, out int elementOffset) || + elementOffset < 0) + { + // Either there's no overlap between the source and the destination, or there's overlap but the + // destination starts at or before the source. That means we can safely iterate from beginning + // to end of the source and not have to worry about writing into the destination and clobbering + // source data we haven't yet read. + + int i = 0; + + if (Vector256.IsHardwareAccelerated) + { + while (i <= source.Length - Vector256.Count) + { + Vector256.StoreUnsafe(TReverser.Reverse(Vector256.LoadUnsafe(ref sourceRef, (uint)i)), ref destRef, (uint)i); + i += Vector256.Count; + } + } + + if (Vector128.IsHardwareAccelerated) + { + while (i <= source.Length - Vector128.Count) + { + Vector128.StoreUnsafe(TReverser.Reverse(Vector128.LoadUnsafe(ref sourceRef, (uint)i)), ref destRef, (uint)i); + i += Vector128.Count; + } + } + + while (i < source.Length) + { + Unsafe.Add(ref destRef, i) = TReverser.Reverse(Unsafe.Add(ref sourceRef, i)); + i++; + } + } + else + { + // There's overlap between the source and the destination, and the source starts before the destination. + // That means if we were to iterate from beginning to end, reading from the source and writing to the + // destination, we'd overwrite source elements not yet read. To avoid that, we iterate from end to beginning. + + int i = source.Length; + + if (Vector256.IsHardwareAccelerated) + { + while (i >= Vector256.Count) + { + i -= Vector256.Count; + Vector256.StoreUnsafe(TReverser.Reverse(Vector256.LoadUnsafe(ref sourceRef, (uint)i)), ref destRef, (uint)i); + } + } + + if (Vector128.IsHardwareAccelerated) + { + while (i >= Vector128.Count) + { + i -= Vector128.Count; + Vector128.StoreUnsafe(TReverser.Reverse(Vector128.LoadUnsafe(ref sourceRef, (uint)i)), ref destRef, (uint)i); + } + } + + while (i > 0) + { + i--; + Unsafe.Add(ref destRef, i) = TReverser.Reverse(Unsafe.Add(ref sourceRef, i)); + } + } + } + + private interface IEndiannessReverser where T : struct + { + static abstract T Reverse(T value); + static abstract Vector128 Reverse(Vector128 vector); + static abstract Vector256 Reverse(Vector256 vector); + } + + /// + [CLSCompliant(false)] + public static void ReverseEndianness(ReadOnlySpan source, Span destination) => + ReverseEndianness(MemoryMarshal.Cast(source), MemoryMarshal.Cast(destination)); + + /// + public static void ReverseEndianness(ReadOnlySpan source, Span destination) + { + if (destination.Length < source.Length) + { + ThrowDestinationTooSmall(); + } + + if (Unsafe.AreSame(ref MemoryMarshal.GetReference(source), ref MemoryMarshal.GetReference(destination)) || + !source.Overlaps(destination, out int elementOffset) || + elementOffset < 0) + { + // Iterate from beginning to end + for (int i = 0; i < source.Length; i++) + { + destination[i] = ReverseEndianness(source[i]); + } + } + else + { + // Iterate from end to beginning + for (int i = source.Length - 1; i >= 0; i--) + { + destination[i] = ReverseEndianness(source[i]); + } + } + } + + [DoesNotReturn] + private static void ThrowDestinationTooSmall() => + throw new ArgumentException(SR.Arg_BufferTooSmall, "destination"); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/Reader.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/Reader.cs index 91b292a..540f873 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/Reader.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Binary/Reader.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types @@ -54,17 +55,17 @@ namespace System.Buffers.Binary [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ReverseEndianness(long value) => (long)ReverseEndianness((ulong)value); - /// - /// Reverses a signed native-sized integral value - performs an endianness swap - /// + /// Reverses a primitive value by performing an endianness swap of the specified value. + /// The value to reverse. + /// The reversed value. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static nint ReverseEndianness(nint value) => (nint)ReverseEndianness((nint_t)value); + public static nint ReverseEndianness(nint value) => (nint)ReverseEndianness((nint_t)value); - /// - /// Reverses a signed 128-bit integral value - performs an endianness swap - /// + /// Reverses a primitive value by performing an endianness swap of the specified value. + /// The value to reverse. + /// The reversed value. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Int128 ReverseEndianness(Int128 value) + public static Int128 ReverseEndianness(Int128 value) { return new Int128( ReverseEndianness(value.Lower), @@ -151,17 +152,19 @@ namespace System.Buffers.Binary + ReverseEndianness((uint)(value >> 32)); } - /// - /// Reverses an unsigned native-sized integral value - performs an endianness swap - /// + /// Reverses a primitive value by performing an endianness swap of the specified value. + /// The value to reverse. + /// The reversed value. + [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static nuint ReverseEndianness(nuint value) => (nuint)ReverseEndianness((nuint_t)value); + public static nuint ReverseEndianness(nuint value) => (nuint)ReverseEndianness((nuint_t)value); - /// - /// Reverses an unsigned 128-bit integral value - performs an endianness swap - /// + /// Reverses a primitive value by performing an endianness swap of the specified value. + /// The value to reverse. + /// The reversed value. + [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static UInt128 ReverseEndianness(UInt128 value) + public static UInt128 ReverseEndianness(UInt128 value) { return new UInt128( ReverseEndianness(value.Lower), -- 2.7.4