// 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 CommunityToolkit.HighPerformance.Helpers.Internals; /// /// Helpers to process sequences of values by reference with a given step. /// internal static class RefEnumerableHelper { /// /// Clears a target memory area. /// /// The type of values to clear. /// A reference to the start of the memory area. /// The number of items in the memory area. /// The number of items between each consecutive target value. public static void Clear(ref T r0, nint length, nint step) { nint offset = 0; // Main loop with 8 unrolled iterations while (length >= 8) { Unsafe.Add(ref r0, offset) = default!; Unsafe.Add(ref r0, offset += step) = default!; Unsafe.Add(ref r0, offset += step) = default!; Unsafe.Add(ref r0, offset += step) = default!; Unsafe.Add(ref r0, offset += step) = default!; Unsafe.Add(ref r0, offset += step) = default!; Unsafe.Add(ref r0, offset += step) = default!; Unsafe.Add(ref r0, offset += step) = default!; length -= 8; offset += step; } if (length >= 4) { Unsafe.Add(ref r0, offset) = default!; Unsafe.Add(ref r0, offset += step) = default!; Unsafe.Add(ref r0, offset += step) = default!; Unsafe.Add(ref r0, offset += step) = default!; length -= 4; offset += step; } // Clear the remaining values while (length > 0) { Unsafe.Add(ref r0, offset) = default!; length -= 1; offset += step; } } /// /// Copies a sequence of discontiguous items from one memory area to another. /// /// The type of items to copy. /// The source reference to copy from. /// The target reference to copy to. /// The total number of items to copy. /// The step between consecutive items in the memory area pointed to by . public static void CopyTo(ref T sourceRef, ref T destinationRef, nint length, nint sourceStep) { nint sourceOffset = 0; nint destinationOffset = 0; while (length >= 8) { Unsafe.Add(ref destinationRef, destinationOffset + 0) = Unsafe.Add(ref sourceRef, sourceOffset); Unsafe.Add(ref destinationRef, destinationOffset + 1) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset + 2) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset + 3) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset + 4) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset + 5) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset + 6) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset + 7) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); length -= 8; sourceOffset += sourceStep; destinationOffset += 8; } if (length >= 4) { Unsafe.Add(ref destinationRef, destinationOffset + 0) = Unsafe.Add(ref sourceRef, sourceOffset); Unsafe.Add(ref destinationRef, destinationOffset + 1) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset + 2) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset + 3) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); length -= 4; sourceOffset += sourceStep; destinationOffset += 4; } while (length > 0) { Unsafe.Add(ref destinationRef, destinationOffset) = Unsafe.Add(ref sourceRef, sourceOffset); length -= 1; sourceOffset += sourceStep; destinationOffset += 1; } } /// /// Copies a sequence of discontiguous items from one memory area to another. /// /// The type of items to copy. /// The source reference to copy from. /// The target reference to copy to. /// The total number of items to copy. /// The step between consecutive items in the memory area pointed to by . /// The step between consecutive items in the memory area pointed to by . public static void CopyTo(ref T sourceRef, ref T destinationRef, nint length, nint sourceStep, nint destinationStep) { nint sourceOffset = 0; nint destinationOffset = 0; while (length >= 8) { Unsafe.Add(ref destinationRef, destinationOffset) = Unsafe.Add(ref sourceRef, sourceOffset); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); length -= 8; sourceOffset += sourceStep; destinationOffset += destinationStep; } if (length >= 4) { Unsafe.Add(ref destinationRef, destinationOffset) = Unsafe.Add(ref sourceRef, sourceOffset); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); Unsafe.Add(ref destinationRef, destinationOffset += destinationStep) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep); length -= 4; sourceOffset += sourceStep; destinationOffset += destinationStep; } while (length > 0) { Unsafe.Add(ref destinationRef, destinationOffset) = Unsafe.Add(ref sourceRef, sourceOffset); length -= 1; sourceOffset += sourceStep; destinationOffset += destinationStep; } } /// /// Copies a sequence of discontiguous items from one memory area to another. This mirrors /// , but refers to instead. /// /// The type of items to copy. /// The source reference to copy from. /// The target reference to copy to. /// The total number of items to copy. /// The step between consecutive items in the memory area pointed to by . public static void CopyFrom(ref T sourceRef, ref T destinationRef, nint length, nint sourceStep) { nint sourceOffset = 0; nint destinationOffset = 0; while (length >= 8) { Unsafe.Add(ref destinationRef, destinationOffset) = Unsafe.Add(ref sourceRef, sourceOffset); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 1); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 2); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 3); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 4); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 5); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 6); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 7); length -= 8; sourceOffset += 8; destinationOffset += sourceStep; } if (length >= 4) { Unsafe.Add(ref destinationRef, destinationOffset) = Unsafe.Add(ref sourceRef, sourceOffset); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 1); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 2); Unsafe.Add(ref destinationRef, destinationOffset += sourceStep) = Unsafe.Add(ref sourceRef, sourceOffset + 3); length -= 4; sourceOffset += 4; destinationOffset += sourceStep; } while (length > 0) { Unsafe.Add(ref destinationRef, destinationOffset) = Unsafe.Add(ref sourceRef, sourceOffset); length -= 1; sourceOffset += 1; destinationOffset += sourceStep; } } /// /// Fills a target memory area. /// /// The type of values to fill. /// A reference to the start of the memory area. /// The number of items in the memory area. /// The number of items between each consecutive target value. /// The value to assign to every item in the target memory area. public static void Fill(ref T r0, nint length, nint step, T value) { nint offset = 0; while (length >= 8) { Unsafe.Add(ref r0, offset) = value; Unsafe.Add(ref r0, offset += step) = value; Unsafe.Add(ref r0, offset += step) = value; Unsafe.Add(ref r0, offset += step) = value; Unsafe.Add(ref r0, offset += step) = value; Unsafe.Add(ref r0, offset += step) = value; Unsafe.Add(ref r0, offset += step) = value; Unsafe.Add(ref r0, offset += step) = value; length -= 8; offset += step; } if (length >= 4) { Unsafe.Add(ref r0, offset) = value; Unsafe.Add(ref r0, offset += step) = value; Unsafe.Add(ref r0, offset += step) = value; Unsafe.Add(ref r0, offset += step) = value; length -= 4; offset += step; } while (length > 0) { Unsafe.Add(ref r0, offset) = value; length -= 1; offset += step; } } }