namespace QWERTYkez.Mensura.Extensions; internal static partial class CollectionsPow3Extensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double QuickPow3(this double base_Value) => base_Value * base_Value * base_Value; // === ТРЕТЬЯ СТЕПЕНЬ ========================================== // === Pow3Core === SIMD internal static void Pow3Core(this ReadOnlySpan units, int len, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { // Делаем реинтерпретацию памяти без выделений и копирований ReadOnlySpan srcDouble = MemoryMarshal.Cast(units[..len]); Span dstDouble = MemoryMarshal.Cast(destination[..len]); int i = 0; // Используем SIMD. Vector автоматически выберет AVX2 (4 элемента) или AVX-512 (8 элементов) if (Vector.IsHardwareAccelerated && len >= Vector.Count) { ref double srcStart = ref MemoryMarshal.GetReference(srcDouble); ref double dstStart = ref MemoryMarshal.GetReference(dstDouble); int limit = len - Vector.Count; for (; i <= limit; i += Vector.Count) { ref double srcCurrent = ref Unsafe.Add(ref srcStart, i); ref double dstCurrent = ref Unsafe.Add(ref dstStart, i); // Загружаем вектор, умножаем сам на себя (квадрат) и сохраняем Vector v = Unsafe.As>(ref srcCurrent); Unsafe.As>(ref dstCurrent) = v * v * v; } } // Добираем остаток элементов, если длина не кратна размеру вектора for (; i < len; i++) { double val = srcDouble[i]; dstDouble[i] = val * val * val; } } internal static void Pow3Core(this ReadOnlySpan units, int len, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { // 1. Получаем низкоуровневые ссылки на первый элемент каждого Span ref T? srcRef = ref MemoryMarshal.GetReference(units); ref R? dstRef = ref MemoryMarshal.GetReference(destination); // 2. Делаем каст самих ref-ссылок в наш мимик. Компилятор это пропускает. ref NullableDoubleMimic srcStart = ref Unsafe.As(ref srcRef); ref NullableDoubleMimic dstStart = ref Unsafe.As(ref dstRef); int i = 0; int limit = len - 4; // Loop Unrolling (Развёртка) for (; i <= limit; i += 4) { ref var s0 = ref Unsafe.Add(ref srcStart, i); ref var s1 = ref Unsafe.Add(ref srcStart, i + 1); ref var s2 = ref Unsafe.Add(ref srcStart, i + 2); ref var s3 = ref Unsafe.Add(ref srcStart, i + 3); ref var d0 = ref Unsafe.Add(ref dstStart, i); ref var d1 = ref Unsafe.Add(ref dstStart, i + 1); ref var d2 = ref Unsafe.Add(ref dstStart, i + 2); ref var d3 = ref Unsafe.Add(ref dstStart, i + 3); d0.Value = s0.Value * s0.Value * s0.Value; d0.HasValue = s0.HasValue; d1.Value = s1.Value * s1.Value * s1.Value; d1.HasValue = s1.HasValue; d2.Value = s2.Value * s2.Value * s2.Value; d2.HasValue = s2.HasValue; d3.Value = s3.Value * s3.Value * s3.Value; d3.HasValue = s3.HasValue; } // Добираем остатки for (; i < len; i++) { ref var s = ref Unsafe.Add(ref srcStart, i); ref var d = ref Unsafe.Add(ref dstStart, i); d.Value = s.Value * s.Value * s.Value; d.HasValue = s.HasValue; } } // === ReadOnlySpan internal static void Pow3(this ReadOnlySpan units, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { int len = units.Length; if (len == 0) return; if (len > destination.Length) throw new ArgumentException("Целевой буфер destination меньше исходного source."); units.Pow3Core(len, destination); } internal static void Pow3(this ReadOnlySpan units, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { int len = units.Length; if (len == 0) return; if (len > destination.Length) throw new ArgumentException("Целевой буфер destination меньше исходного source."); units.Pow3Core(len, destination); } // === Array === internal static R[] Pow3(this T[] units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return null!; int len = units.Length; if (len == 0) return []; var result = new R[len]; units.Pow3Core(len, result); return result; } internal static R?[] Pow3(this T?[] units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return null!; int len = units.Length; if (len == 0) return []; var result = new R?[len]; units.Pow3Core(len, result); return result; } // === List === internal static List Pow3(this List units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return null!; int count = units.Count; if (count == 0) return []; var result = new R[count]; CollectionsMarshal.AsSpan(units).Pow3Core(count, result); return result.WrapAsList(); } internal static List Pow3(this List units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return null!; int count = units.Count; if (count == 0) return []; var result = new R?[count]; CollectionsMarshal.AsSpan(units).Pow3Core(count, result); return result.WrapAsList(); } // === IReadOnlyCollection === internal static void Pow3(this IReadOnlyCollection units, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return; int count = units.Count; if (count == 0) return; if (destination.Length < count) throw new ArgumentException("Destination too short"); if (units is T[] array) { array.Pow3Core(count, destination); return; } if (units is List list) { CollectionsMarshal.AsSpan(list).Pow3Core(count, destination); return; } int i = 0; foreach (var item in units) destination[i++] = item.ToDouble().QuickPow3().ToUnit(); } internal static void Pow3(this IReadOnlyCollection units, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return; int count = units.Count; if (count == 0) return; if (destination.Length < count) throw new ArgumentException("Destination too short"); if (units is T?[] array) { array.Pow3Core(count, destination); return; } if (units is List list) { CollectionsMarshal.AsSpan(list).Pow3Core(count, destination); return; } int i = 0; foreach (var item in units) destination[i++] = item.Protected().QuickPow3().ToUnit(); } // === IEnumerable + yeild === static IEnumerable PowIterator3(IEnumerable units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { foreach (var item in units) yield return (item.ToDouble().QuickPow3()).ToUnit(); } static IEnumerable PowNullableIterator3(IEnumerable units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { foreach (var item in units) yield return item.Protected().QuickPow3().ToUnit(); } // === IEnumerable === internal static IEnumerable Pow3(this IEnumerable units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return null!; if (units is T[] array) return array.Pow3(); if (units is List list) return list.Pow3(); if (units is IReadOnlyCollection roc) { var arr = roc.ToArray(); arr.Pow3Core(arr.Length, arr); return arr.ReCast(); } else return PowIterator3(units); } internal static IEnumerable Pow3(this IEnumerable units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return null!; if (units is T?[] array) return array.Pow3(); if (units is List list) return list.Pow3(); if (units is IReadOnlyCollection roc) { var arr = roc.ToArray(); arr.Pow3Core(arr.Length, arr); return arr.ReCast(); } else return PowNullableIterator3(units); } }