// 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;
}
}
}