diff --git a/src/SharpCompress/Algorithms/Adler32.cs b/src/SharpCompress/Algorithms/Adler32.cs
new file mode 100644
index 00000000..e98c864e
--- /dev/null
+++ b/src/SharpCompress/Algorithms/Adler32.cs
@@ -0,0 +1,420 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+#if !NETSTANDARD2_0 && !NETSTANDARD2_1 && !NETFRAMEWORK
+#define SUPPORTS_RUNTIME_INTRINSICS
+#define SUPPORTS_HOTPATH
+#endif
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
+
+#pragma warning disable IDE0007 // Use implicit type
+namespace SharpCompress.Algorithms
+{
+ ///
+ /// Calculates the 32 bit Adler checksum of a given buffer according to
+ /// RFC 1950. ZLIB Compressed Data Format Specification version 3.3)
+ ///
+ internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Compression/Zlib/Adler32.cs
+ {
+ ///
+ /// Global inlining options. Helps temporarily disable inlining for better profiler output.
+ ///
+ private static class InliningOptions // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Common/Helpers/InliningOptions.cs
+ {
+ ///
+ /// regardless of the build conditions.
+ ///
+ public const MethodImplOptions AlwaysInline = MethodImplOptions.AggressiveInlining;
+#if PROFILING
+ public const MethodImplOptions HotPath = MethodImplOptions.NoInlining;
+ public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining;
+#else
+#if SUPPORTS_HOTPATH
+ public const MethodImplOptions HotPath = MethodImplOptions.AggressiveOptimization;
+#else
+ public const MethodImplOptions HotPath = MethodImplOptions.AggressiveInlining;
+#endif
+ public const MethodImplOptions ShortMethod = MethodImplOptions.AggressiveInlining;
+#endif
+ public const MethodImplOptions ColdPath = MethodImplOptions.NoInlining;
+ }
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ ///
+ /// Provides optimized static methods for trigonometric, logarithmic,
+ /// and other common mathematical functions.
+ ///
+ private static class Numerics // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Common/Helpers/Numerics.cs
+ {
+ ///
+ /// Reduces elements of the vector into one sum.
+ ///
+ /// The accumulator to reduce.
+ /// The sum of all elements.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int ReduceSum(Vector256 accumulator)
+ {
+ // Add upper lane to lower lane.
+ Vector128 vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper());
+
+ // Add odd to even.
+ vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_11_01_01));
+
+ // Add high to low.
+ vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10));
+
+ return Sse2.ConvertToInt32(vsum);
+ }
+
+ ///
+ /// Reduces even elements of the vector into one sum.
+ ///
+ /// The accumulator to reduce.
+ /// The sum of even elements.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int EvenReduceSum(Vector256 accumulator)
+ {
+ Vector128 vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper()); // add upper lane to lower lane
+ vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10)); // add high to low
+
+ // Vector128.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882
+ return Sse2.ConvertToInt32(vsum);
+ }
+ }
+#endif
+
+ ///
+ /// The default initial seed value of a Adler32 checksum calculation.
+ ///
+ public const uint SeedValue = 1U;
+
+ // Largest prime smaller than 65536
+ private const uint BASE = 65521;
+
+ // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
+ private const uint NMAX = 5552;
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ private const int MinBufferSize = 64;
+
+ private const int BlockSize = 1 << 5;
+
+ // The C# compiler emits this as a compile-time constant embedded in the PE file.
+ private static ReadOnlySpan Tap1Tap2 => new byte[]
+ {
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, // tap1
+ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 // tap2
+ };
+#endif
+
+ ///
+ /// Calculates the Adler32 checksum with the bytes taken from the span.
+ ///
+ /// The readonly span of bytes.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static uint Calculate(ReadOnlySpan buffer)
+ => Calculate(SeedValue, buffer);
+
+ ///
+ /// Calculates the Adler32 checksum with the bytes taken from the span and seed.
+ ///
+ /// The input Adler32 value.
+ /// The readonly span of bytes.
+ /// The .
+ [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
+ public static uint Calculate(uint adler, ReadOnlySpan buffer)
+ {
+ if (buffer.IsEmpty)
+ {
+ return adler;
+ }
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ if (Avx2.IsSupported && buffer.Length >= MinBufferSize)
+ {
+ return CalculateAvx2(adler, buffer);
+ }
+
+ if (Ssse3.IsSupported && buffer.Length >= MinBufferSize)
+ {
+ return CalculateSse(adler, buffer);
+ }
+
+ return CalculateScalar(adler, buffer);
+#else
+ return CalculateScalar(adler, buffer);
+#endif
+ }
+
+ // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/adler32_simd.c
+#if SUPPORTS_RUNTIME_INTRINSICS
+ [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
+ private static unsafe uint CalculateSse(uint adler, ReadOnlySpan buffer)
+ {
+ uint s1 = adler & 0xFFFF;
+ uint s2 = (adler >> 16) & 0xFFFF;
+
+ // Process the data in blocks.
+ uint length = (uint)buffer.Length;
+ uint blocks = length / BlockSize;
+ length -= blocks * BlockSize;
+
+ fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer))
+ {
+ fixed (byte* tapPtr = &MemoryMarshal.GetReference(Tap1Tap2))
+ {
+ byte* localBufferPtr = bufferPtr;
+
+ // _mm_setr_epi8 on x86
+ Vector128 tap1 = Sse2.LoadVector128((sbyte*)tapPtr);
+ Vector128 tap2 = Sse2.LoadVector128((sbyte*)(tapPtr + 0x10));
+ Vector128 zero = Vector128.Zero;
+ var ones = Vector128.Create((short)1);
+
+ while (blocks > 0)
+ {
+ uint n = NMAX / BlockSize; /* The NMAX constraint. */
+ if (n > blocks)
+ {
+ n = blocks;
+ }
+
+ blocks -= n;
+
+ // Process n blocks of data. At most NMAX data bytes can be
+ // processed before s2 must be reduced modulo BASE.
+ Vector128 v_ps = Vector128.CreateScalar(s1 * n);
+ Vector128 v_s2 = Vector128.CreateScalar(s2);
+ Vector128 v_s1 = Vector128.Zero;
+
+ do
+ {
+ // Load 32 input bytes.
+ Vector128 bytes1 = Sse3.LoadDquVector128(localBufferPtr);
+ Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 0x10);
+
+ // Add previous block byte sum to v_ps.
+ v_ps = Sse2.Add(v_ps, v_s1);
+
+ // Horizontally add the bytes for s1, multiply-adds the
+ // bytes by [ 32, 31, 30, ... ] for s2.
+ v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsUInt32());
+ Vector128 mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1);
+ v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones).AsUInt32());
+
+ v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsUInt32());
+ Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2);
+ v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32());
+
+ localBufferPtr += BlockSize;
+ }
+ while (--n > 0);
+
+ v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5));
+
+ // Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
+ const byte S2301 = 0b1011_0001; // A B C D -> B A D C
+ const byte S1032 = 0b0100_1110; // A B C D -> C D A B
+
+ v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032));
+
+ s1 += v_s1.ToScalar();
+
+ v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301));
+ v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032));
+
+ s2 = v_s2.ToScalar();
+
+ // Reduce.
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+
+ if (length > 0)
+ {
+ HandleLeftOver(localBufferPtr, length, ref s1, ref s2);
+ }
+
+ return s1 | (s2 << 16);
+ }
+ }
+ }
+
+ // Based on: https://github.com/zlib-ng/zlib-ng/blob/develop/arch/x86/adler32_avx2.c
+ [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
+ public static unsafe uint CalculateAvx2(uint adler, ReadOnlySpan buffer)
+ {
+ uint s1 = adler & 0xFFFF;
+ uint s2 = (adler >> 16) & 0xFFFF;
+ uint length = (uint)buffer.Length;
+
+ fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer))
+ {
+ byte* localBufferPtr = bufferPtr;
+
+ Vector256 zero = Vector256.Zero;
+ var dot3v = Vector256.Create((short)1);
+ var dot2v = Vector256.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
+
+ // Process n blocks of data. At most NMAX data bytes can be
+ // processed before s2 must be reduced modulo BASE.
+ var vs1 = Vector256.CreateScalar(s1);
+ var vs2 = Vector256.CreateScalar(s2);
+
+ while (length >= 32)
+ {
+ int k = length < NMAX ? (int)length : (int)NMAX;
+ k -= k % 32;
+ length -= (uint)k;
+
+ Vector256 vs10 = vs1;
+ Vector256 vs3 = Vector256.Zero;
+
+ while (k >= 32)
+ {
+ // Load 32 input bytes.
+ Vector256 block = Avx.LoadVector256(localBufferPtr);
+
+ // Sum of abs diff, resulting in 2 x int32's
+ Vector256 vs1sad = Avx2.SumAbsoluteDifferences(block, zero);
+
+ vs1 = Avx2.Add(vs1, vs1sad.AsUInt32());
+ vs3 = Avx2.Add(vs3, vs10);
+
+ // sum 32 uint8s to 16 shorts.
+ Vector256 vshortsum2 = Avx2.MultiplyAddAdjacent(block, dot2v);
+
+ // sum 16 shorts to 8 uint32s.
+ Vector256 vsum2 = Avx2.MultiplyAddAdjacent(vshortsum2, dot3v);
+
+ vs2 = Avx2.Add(vsum2.AsUInt32(), vs2);
+ vs10 = vs1;
+
+ localBufferPtr += BlockSize;
+ k -= 32;
+ }
+
+ // Defer the multiplication with 32 to outside of the loop.
+ vs3 = Avx2.ShiftLeftLogical(vs3, 5);
+ vs2 = Avx2.Add(vs2, vs3);
+
+ s1 = (uint)Numerics.EvenReduceSum(vs1.AsInt32());
+ s2 = (uint)Numerics.ReduceSum(vs2.AsInt32());
+
+ s1 %= BASE;
+ s2 %= BASE;
+
+ vs1 = Vector256.CreateScalar(s1);
+ vs2 = Vector256.CreateScalar(s2);
+ }
+
+ if (length > 0)
+ {
+ HandleLeftOver(localBufferPtr, length, ref s1, ref s2);
+ }
+
+ return s1 | (s2 << 16);
+ }
+ }
+
+ private static unsafe void HandleLeftOver(byte* localBufferPtr, uint length, ref uint s1, ref uint s2)
+ {
+ if (length >= 16)
+ {
+ s2 += s1 += localBufferPtr[0];
+ s2 += s1 += localBufferPtr[1];
+ s2 += s1 += localBufferPtr[2];
+ s2 += s1 += localBufferPtr[3];
+ s2 += s1 += localBufferPtr[4];
+ s2 += s1 += localBufferPtr[5];
+ s2 += s1 += localBufferPtr[6];
+ s2 += s1 += localBufferPtr[7];
+ s2 += s1 += localBufferPtr[8];
+ s2 += s1 += localBufferPtr[9];
+ s2 += s1 += localBufferPtr[10];
+ s2 += s1 += localBufferPtr[11];
+ s2 += s1 += localBufferPtr[12];
+ s2 += s1 += localBufferPtr[13];
+ s2 += s1 += localBufferPtr[14];
+ s2 += s1 += localBufferPtr[15];
+
+ localBufferPtr += 16;
+ length -= 16;
+ }
+
+ while (length-- > 0)
+ {
+ s2 += s1 += *localBufferPtr++;
+ }
+
+ if (s1 >= BASE)
+ {
+ s1 -= BASE;
+ }
+
+ s2 %= BASE;
+ }
+#endif
+
+ [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
+ private static unsafe uint CalculateScalar(uint adler, ReadOnlySpan buffer)
+ {
+ uint s1 = adler & 0xFFFF;
+ uint s2 = (adler >> 16) & 0xFFFF;
+ uint k;
+
+ fixed (byte* bufferPtr = buffer)
+ {
+ var localBufferPtr = bufferPtr;
+ uint length = (uint)buffer.Length;
+
+ while (length > 0)
+ {
+ k = length < NMAX ? length : NMAX;
+ length -= k;
+
+ while (k >= 16)
+ {
+ s2 += s1 += localBufferPtr[0];
+ s2 += s1 += localBufferPtr[1];
+ s2 += s1 += localBufferPtr[2];
+ s2 += s1 += localBufferPtr[3];
+ s2 += s1 += localBufferPtr[4];
+ s2 += s1 += localBufferPtr[5];
+ s2 += s1 += localBufferPtr[6];
+ s2 += s1 += localBufferPtr[7];
+ s2 += s1 += localBufferPtr[8];
+ s2 += s1 += localBufferPtr[9];
+ s2 += s1 += localBufferPtr[10];
+ s2 += s1 += localBufferPtr[11];
+ s2 += s1 += localBufferPtr[12];
+ s2 += s1 += localBufferPtr[13];
+ s2 += s1 += localBufferPtr[14];
+ s2 += s1 += localBufferPtr[15];
+
+ localBufferPtr += 16;
+ k -= 16;
+ }
+
+ while (k-- > 0)
+ {
+ s2 += s1 += *localBufferPtr++;
+ }
+
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+
+ return (s2 << 16) | s1;
+ }
+ }
+ }
+}
diff --git a/src/SharpCompress/Algorithms/Alder32.cs b/src/SharpCompress/Algorithms/Alder32.cs
deleted file mode 100644
index 9a353993..00000000
--- a/src/SharpCompress/Algorithms/Alder32.cs
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the GNU Affero General Public License, Version 3.
-
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-#if !NETSTANDARD2_0 && !NETSTANDARD2_1 && !NETFRAMEWORK
-using System.Runtime.Intrinsics;
-using System.Runtime.Intrinsics.X86;
-#endif
-
-namespace SharpCompress.Algorithms
-{
- ///
- /// Calculates the 32 bit Adler checksum of a given buffer according to
- /// RFC 1950. ZLIB Compressed Data Format Specification version 3.3)
- ///
- internal static class Adler32
- {
- ///
- /// The default initial seed value of a Adler32 checksum calculation.
- ///
- public const uint SeedValue = 1U;
-
-#if !NETSTANDARD2_0 && !NETSTANDARD2_1 && !NETFRAMEWORK
- private const int MinBufferSize = 64;
-#endif
-
- // Largest prime smaller than 65536
- private const uint BASE = 65521;
-
- // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
- private const uint NMAX = 5552;
-
- ///
- /// Calculates the Adler32 checksum with the bytes taken from the span.
- ///
- /// The readonly span of bytes.
- /// The .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint Calculate(ReadOnlySpan buffer)
- {
- return Calculate(SeedValue, buffer);
- }
-
- ///
- /// Calculates the Adler32 checksum with the bytes taken from the span and seed.
- ///
- /// The input Adler32 value.
- /// The readonly span of bytes.
- /// The .
- public static uint Calculate(uint adler, ReadOnlySpan buffer)
- {
-#if !NETSTANDARD2_0 && !NETSTANDARD2_1 && !NETFRAMEWORK
- if (Sse3.IsSupported && buffer.Length >= MinBufferSize)
- {
- return CalculateSse(adler, buffer);
- }
-
- return CalculateScalar(adler, buffer);
-#else
- return CalculateScalar(adler, buffer);
-#endif
- }
-
- // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/adler32_simd.c
-#if !NETSTANDARD2_0 && !NETSTANDARD2_1 && !NETFRAMEWORK
- private static unsafe uint CalculateSse(uint adler, ReadOnlySpan buffer)
- {
- uint s1 = adler & 0xFFFF;
- uint s2 = (adler >> 16) & 0xFFFF;
-
- // Process the data in blocks.
- const int BLOCK_SIZE = 1 << 5;
-
- uint length = (uint)buffer.Length;
- uint blocks = length / BLOCK_SIZE;
- length -= blocks * BLOCK_SIZE;
-
- int index = 0;
- fixed (byte* bufferPtr = &buffer[0])
- {
- index += (int)blocks * BLOCK_SIZE;
- var localBufferPtr = bufferPtr;
-
- // _mm_setr_epi8 on x86
- var tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17);
- var tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
- Vector128 zero = Vector128.Zero;
- var ones = Vector128.Create((short)1);
-
- while (blocks > 0)
- {
- uint n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */
- if (n > blocks)
- {
- n = blocks;
- }
-
- blocks -= n;
-
- // Process n blocks of data. At most NMAX data bytes can be
- // processed before s2 must be reduced modulo BASE.
- Vector128 v_ps = Vector128.CreateScalar(s1 * n).AsInt32();
- Vector128 v_s2 = Vector128.CreateScalar(s2).AsInt32();
- Vector128 v_s1 = Vector128.Zero;
-
- do
- {
- // Load 32 input bytes.
- Vector128 bytes1 = Sse3.LoadDquVector128(localBufferPtr);
- Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 16);
-
- // Add previous block byte sum to v_ps.
- v_ps = Sse2.Add(v_ps, v_s1);
-
- // Horizontally add the bytes for s1, multiply-adds the
- // bytes by [ 32, 31, 30, ... ] for s2.
- v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsInt32());
- Vector128 mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1);
- v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones));
-
- v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsInt32());
- Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2);
- v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones));
-
- localBufferPtr += BLOCK_SIZE;
- }
- while (--n > 0);
-
- v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5));
-
- // Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
- const byte S2301 = 0b1011_0001; // A B C D -> B A D C
- const byte S1032 = 0b0100_1110; // A B C D -> C D A B
-
- v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S2301));
- v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032));
-
- s1 += (uint)v_s1.ToScalar();
-
- v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301));
- v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032));
-
- s2 = (uint)v_s2.ToScalar();
-
- // Reduce.
- s1 %= BASE;
- s2 %= BASE;
- }
- }
-
- ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
-
- if (length > 0)
- {
- if (length >= 16)
- {
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- length -= 16;
- }
-
- while (length-- > 0)
- {
- s2 += s1 += Unsafe.Add(ref bufferRef, index++);
- }
-
- if (s1 >= BASE)
- {
- s1 -= BASE;
- }
-
- s2 %= BASE;
- }
-
- return s1 | (s2 << 16);
- }
-#endif
-
- private static uint CalculateScalar(uint adler, ReadOnlySpan buffer)
- {
- uint s1 = adler & 0xFFFF;
- uint s2 = (adler >> 16) & 0xFFFF;
- uint k;
-
- ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
- uint length = (uint)buffer.Length;
- int index = 0;
-
- while (length > 0)
- {
- k = length < NMAX ? length : NMAX;
- length -= k;
-
- while (k >= 16)
- {
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- k -= 16;
- }
-
- if (k != 0)
- {
- do
- {
- s1 += Unsafe.Add(ref bufferRef, index++);
- s2 += s1;
- }
- while (--k != 0);
- }
-
- s1 %= BASE;
- s2 %= BASE;
- }
-
- return (s2 << 16) | s1;
- }
- }
-}