Pow2 Pow3 Sqrt2 Sqrt3
This commit is contained in:
@@ -23,7 +23,7 @@ internal static partial class CastExtensions
|
||||
{
|
||||
// Берем адрес управляемого объекта List в памяти
|
||||
// Объект передается по ref-ссылке, преобразуется в указатель
|
||||
ref var mimic = ref Unsafe.As<List<T>, ListLayoutMimic<T>>(ref list);
|
||||
ref var mimic = ref Unsafe.As<List<T>, Mimics<T>>(ref list);
|
||||
|
||||
// Меняем приватный размер напрямую в памяти объекта!
|
||||
mimic.Size = count;
|
||||
@@ -40,7 +40,7 @@ internal static partial class CastExtensions
|
||||
var list = new List<R>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<R>, ListLayoutMimic<T>>(ref list);
|
||||
ref var mimic = ref Unsafe.As<List<R>, Mimics<T>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
@@ -59,7 +59,7 @@ internal static partial class CastExtensions
|
||||
var list = new List<R?>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<R?>, ListLayoutMimic<T?>>(ref list);
|
||||
ref var mimic = ref Unsafe.As<List<R?>, Mimics<T?>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
@@ -77,7 +77,7 @@ internal static partial class CastExtensions
|
||||
var list = new List<double>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<double>, ListLayoutMimic<T>>(ref list);
|
||||
ref var mimic = ref Unsafe.As<List<double>, Mimics<T>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
@@ -95,7 +95,7 @@ internal static partial class CastExtensions
|
||||
var list = new List<double?>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<double?>, ListLayoutMimic<T?>>(ref list);
|
||||
ref var mimic = ref Unsafe.As<List<double?>, Mimics<T?>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
@@ -112,7 +112,7 @@ internal static partial class CastExtensions
|
||||
var list = new List<double>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<double>, ListLayoutMimic<double>>(ref list);
|
||||
ref var mimic = ref Unsafe.As<List<double>, Mimics<double>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
@@ -129,7 +129,7 @@ internal static partial class CastExtensions
|
||||
var list = new List<double?>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<double?>, ListLayoutMimic<double?>>(ref list);
|
||||
ref var mimic = ref Unsafe.As<List<double?>, Mimics<double?>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
|
||||
309
QWERTYkez.Mensura/Extensions/CollectionsPow2Extensions.cs
Normal file
309
QWERTYkez.Mensura/Extensions/CollectionsPow2Extensions.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
namespace QWERTYkez.Mensura.Extensions;
|
||||
|
||||
internal static partial class CollectionsPow2Extensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double QuickPow2(this double base_Value) => base_Value * base_Value;
|
||||
|
||||
|
||||
// === ВТОРАЯ СТЕПЕНЬ ==========================================
|
||||
|
||||
// === Pow2Core2 === SIMD
|
||||
internal static void Pow2Core2<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
// Делаем реинтерпретацию памяти без выделений и копирований
|
||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units[..len]);
|
||||
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination[..len]);
|
||||
|
||||
int i = 0;
|
||||
|
||||
// Используем SIMD. Vector<double> автоматически выберет AVX2 (4 элемента) или AVX-512 (8 элементов)
|
||||
if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
|
||||
{
|
||||
ref double srcStart = ref MemoryMarshal.GetReference(srcDouble);
|
||||
ref double dstStart = ref MemoryMarshal.GetReference(dstDouble);
|
||||
int limit = len - Vector<double>.Count;
|
||||
|
||||
for (; i <= limit; i += Vector<double>.Count)
|
||||
{
|
||||
ref double srcCurrent = ref Unsafe.Add(ref srcStart, i);
|
||||
ref double dstCurrent = ref Unsafe.Add(ref dstStart, i);
|
||||
|
||||
// Загружаем вектор, умножаем сам на себя (квадрат) и сохраняем
|
||||
Vector<double> v = Unsafe.As<double, Vector<double>>(ref srcCurrent);
|
||||
Unsafe.As<double, Vector<double>>(ref dstCurrent) = v * v;
|
||||
}
|
||||
}
|
||||
|
||||
// Добираем остаток элементов, если длина не кратна размеру вектора
|
||||
for (; i < len; i++)
|
||||
{
|
||||
double val = srcDouble[i];
|
||||
dstDouble[i] = val * val;
|
||||
}
|
||||
}
|
||||
internal static void Pow2Core2<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
// 1. Получаем низкоуровневые ссылки на первый элемент каждого Span
|
||||
ref T? srcRef = ref MemoryMarshal.GetReference(units);
|
||||
ref R? dstRef = ref MemoryMarshal.GetReference(destination);
|
||||
|
||||
// 2. Делаем каст самих ref-ссылок в наш мимик. Компилятор это пропускает.
|
||||
ref NullableDoubleMimic srcStart = ref Unsafe.As<T?, NullableDoubleMimic>(ref srcRef);
|
||||
ref NullableDoubleMimic dstStart = ref Unsafe.As<R?, NullableDoubleMimic>(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;
|
||||
d0.HasValue = s0.HasValue;
|
||||
|
||||
d1.Value = s1.Value * s1.Value;
|
||||
d1.HasValue = s1.HasValue;
|
||||
|
||||
d2.Value = s2.Value * s2.Value;
|
||||
d2.HasValue = s2.HasValue;
|
||||
|
||||
d3.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;
|
||||
d.HasValue = s.HasValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === ReadOnlySpan
|
||||
internal static void Pow2<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
int len = units.Length;
|
||||
if (len == 0) return;
|
||||
if (len > destination.Length)
|
||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||
|
||||
units.Pow2Core2(len, destination);
|
||||
}
|
||||
internal static void Pow2<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
int len = units.Length;
|
||||
if (len == 0) return;
|
||||
if (len > destination.Length)
|
||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||
|
||||
units.Pow2Core2(len, destination);
|
||||
}
|
||||
|
||||
// === Array ===
|
||||
internal static R[] Pow2<T, R>(this T[] units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int len = units.Length;
|
||||
if (len == 0) return [];
|
||||
|
||||
var result = new R[len];
|
||||
Pow2(units, result);
|
||||
return result;
|
||||
}
|
||||
internal static R?[] Pow2<T, R>(this T?[] units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int len = units.Length;
|
||||
if (len == 0) return [];
|
||||
|
||||
var result = new R?[len];
|
||||
Pow2(units, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// === List<Length> ===
|
||||
internal static List<R> Pow2<T, R>(this List<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int count = units.Count;
|
||||
if (count == 0) return [];
|
||||
|
||||
var resultArray = new R[count];
|
||||
Pow2(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
internal static List<R?> Pow2<T, R>(this List<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int count = units.Count;
|
||||
if (count == 0) return [];
|
||||
|
||||
var resultArray = new R?[count];
|
||||
Pow2(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
|
||||
// === ICollection<Length> ===
|
||||
internal static void Pow2<T, R>(this ICollection<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Pow2(destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.ToDouble().QuickPow2().ToUnit<R>();
|
||||
}
|
||||
internal static void Pow2<T, R>(this ICollection<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Pow2(destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? item.Value.ToDouble().QuickPow2().ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<Length> ===
|
||||
internal static void Pow2<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Pow2(destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.ToDouble().QuickPow2().ToUnit<R>();
|
||||
}
|
||||
internal static void Pow2<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Pow2(destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? item.Value.ToDouble().QuickPow2().ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IEnumerable<T, R> + yeild ===
|
||||
static IEnumerable<R> Pow2Iterator<T, R>(IEnumerable<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
foreach (var item in units)
|
||||
yield return (item.ToDouble().QuickPow2()).ToUnit<R>();
|
||||
}
|
||||
static IEnumerable<R?> Pow2NullableIterator<T, R>(IEnumerable<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
foreach (var item in units)
|
||||
yield return item.HasValue
|
||||
? item.Value.ToDouble().QuickPow2().ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IEnumerable<Length> ===
|
||||
internal static IEnumerable<R> Pow2<T, R>(this IEnumerable<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Pow2<T, R>();
|
||||
if (units is List<T> list) return list.Pow2<T, R>();
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Pow2Core2(arr.Length, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
arr.Pow2(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
else return Pow2Iterator<T, R>(units);
|
||||
}
|
||||
internal static IEnumerable<R?> Pow2<T, R>(this IEnumerable<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Pow2<T, R>();
|
||||
if (units is List<T?> list) return list.Pow2<T, R>();
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Pow2(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
arr.Pow2(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
else return Pow2NullableIterator<T, R>(units);
|
||||
}
|
||||
}
|
||||
312
QWERTYkez.Mensura/Extensions/CollectionsPow3Extensions.cs
Normal file
312
QWERTYkez.Mensura/Extensions/CollectionsPow3Extensions.cs
Normal file
@@ -0,0 +1,312 @@
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
// === ТРЕТЬЯ СТЕПЕНЬ ==========================================
|
||||
|
||||
// === PowCore3 === SIMD
|
||||
internal static void PowCore3<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
// Делаем реинтерпретацию памяти без выделений и копирований
|
||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units[..len]);
|
||||
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination[..len]);
|
||||
|
||||
int i = 0;
|
||||
|
||||
// Используем SIMD. Vector<double> автоматически выберет AVX2 (4 элемента) или AVX-512 (8 элементов)
|
||||
if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
|
||||
{
|
||||
ref double srcStart = ref MemoryMarshal.GetReference(srcDouble);
|
||||
ref double dstStart = ref MemoryMarshal.GetReference(dstDouble);
|
||||
int limit = len - Vector<double>.Count;
|
||||
|
||||
for (; i <= limit; i += Vector<double>.Count)
|
||||
{
|
||||
ref double srcCurrent = ref Unsafe.Add(ref srcStart, i);
|
||||
ref double dstCurrent = ref Unsafe.Add(ref dstStart, i);
|
||||
|
||||
// Загружаем вектор, умножаем сам на себя (квадрат) и сохраняем
|
||||
Vector<double> v = Unsafe.As<double, Vector<double>>(ref srcCurrent);
|
||||
Unsafe.As<double, Vector<double>>(ref dstCurrent) = v * v * v;
|
||||
}
|
||||
}
|
||||
|
||||
// Добираем остаток элементов, если длина не кратна размеру вектора
|
||||
for (; i < len; i++)
|
||||
{
|
||||
double val = srcDouble[i];
|
||||
dstDouble[i] = val * val * val;
|
||||
}
|
||||
}
|
||||
internal static void PowCore3<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
// 1. Получаем низкоуровневые ссылки на первый элемент каждого Span
|
||||
ref T? srcRef = ref MemoryMarshal.GetReference(units);
|
||||
ref R? dstRef = ref MemoryMarshal.GetReference(destination);
|
||||
|
||||
// 2. Делаем каст самих ref-ссылок в наш мимик. Компилятор это пропускает.
|
||||
ref NullableDoubleMimic srcStart = ref Unsafe.As<T?, NullableDoubleMimic>(ref srcRef);
|
||||
ref NullableDoubleMimic dstStart = ref Unsafe.As<R?, NullableDoubleMimic>(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<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
int len = units.Length;
|
||||
if (len == 0) return;
|
||||
if (len > destination.Length)
|
||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||
|
||||
units.PowCore3(len, destination);
|
||||
}
|
||||
internal static void Pow3<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
int len = units.Length;
|
||||
if (len == 0) return;
|
||||
if (len > destination.Length)
|
||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||
|
||||
units.PowCore3(len, destination);
|
||||
}
|
||||
|
||||
// === Array ===
|
||||
internal static R[] Pow3<T, R>(this T[] units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int len = units.Length;
|
||||
if (len == 0) return [];
|
||||
|
||||
var result = new R[len];
|
||||
Pow3(units, result);
|
||||
return result;
|
||||
}
|
||||
internal static R?[] Pow3<T, R>(this T?[] units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int len = units.Length;
|
||||
if (len == 0) return [];
|
||||
|
||||
var result = new R?[len];
|
||||
Pow3(units, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// === List<Length> ===
|
||||
internal static List<R> Pow3<T, R>(this List<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int count = units.Count;
|
||||
if (count == 0) return [];
|
||||
|
||||
var resultArray = new R[count];
|
||||
Pow3(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
internal static List<R?> Pow3<T, R>(this List<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int count = units.Count;
|
||||
if (count == 0) return [];
|
||||
|
||||
var resultArray = new R?[count];
|
||||
Pow3(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
|
||||
// === ICollection<Length> ===
|
||||
internal static void Pow3<T, R>(this ICollection<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Pow3(destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.ToDouble().QuickPow3().ToUnit<R>();
|
||||
}
|
||||
internal static void Pow3<T, R>(this ICollection<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Pow3(destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? item.Value.ToDouble().QuickPow3().ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<Length> ===
|
||||
internal static void Pow3<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Pow3(destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.ToDouble().QuickPow3().ToUnit<R>();
|
||||
}
|
||||
internal static void Pow3<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Pow3(destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? item.Value.ToDouble().QuickPow3().ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IEnumerable<T, R> + yeild ===
|
||||
static IEnumerable<R> PowIterator3<T, R>(IEnumerable<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
foreach (var item in units)
|
||||
yield return (item.ToDouble().QuickPow3()).ToUnit<R>();
|
||||
}
|
||||
static IEnumerable<R?> PowNullableIterator3<T, R>(IEnumerable<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
foreach (var item in units)
|
||||
yield return item.HasValue
|
||||
? item.Value.ToDouble().QuickPow3().ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IEnumerable<Length> ===
|
||||
internal static IEnumerable<R> Pow3<T, R>(this IEnumerable<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Pow3<T, R>();
|
||||
if (units is List<T> list) return list.Pow3<T, R>();
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.PowCore3(arr.Length, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
arr.Pow3(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
else return PowIterator3<T, R>(units);
|
||||
}
|
||||
internal static IEnumerable<R?> Pow3<T, R>(this IEnumerable<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Pow3<T, R>();
|
||||
if (units is List<T?> list) return list.Pow3<T, R>();
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Pow3(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
arr.Pow3(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
else return PowNullableIterator3<T, R>(units);
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,9 @@ using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace QWERTYkez.Mensura.Extensions;
|
||||
|
||||
internal static partial class CollectionsPowExtensions
|
||||
internal static partial class CollectionsPowNExtensions
|
||||
{
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static double QuickPow(this double base_Value, int exp)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double QuickPow(this double base_Value, int exp)
|
||||
{
|
||||
switch (exp)
|
||||
{
|
||||
317
QWERTYkez.Mensura/Extensions/CollectionsSqrt3Extensions.cs
Normal file
317
QWERTYkez.Mensura/Extensions/CollectionsSqrt3Extensions.cs
Normal file
@@ -0,0 +1,317 @@
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace QWERTYkez.Mensura.Extensions;
|
||||
|
||||
internal static partial class CollectionsSqrt3Extensions
|
||||
{
|
||||
// === SqrtCore3 === SIMD
|
||||
internal static unsafe void SqrtCore3<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||
|
||||
int i = 0;
|
||||
|
||||
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
|
||||
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
|
||||
|
||||
// 1. ПУТЬ AVX (x64 Процессоры Intel/AMD) — обрабатываем по 4 элемента double
|
||||
if (Avx.IsSupported && len >= 4)
|
||||
{
|
||||
int simdEnd = len & ~3;
|
||||
for (; i < simdEnd; i += 4)
|
||||
{
|
||||
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
|
||||
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
|
||||
|
||||
// Получаем указатели через Unsafe.AsPointer
|
||||
double* pSrc = (double*)Unsafe.AsPointer(ref currentSrc);
|
||||
double* pDst = (double*)Unsafe.AsPointer(ref currentDst);
|
||||
|
||||
// Выровненная загрузка (требует, чтобы pSrc был кратен 32)
|
||||
var v = Avx.LoadVector256(pSrc);
|
||||
var sqrtV = Avx.Sqrt(v);
|
||||
// Выровненное сохранение
|
||||
Avx.Store(pDst, sqrtV);
|
||||
}
|
||||
}
|
||||
// 2. ПУТЬ VECTOR (ARM64 / Apple Silicon / Старые CPU без AVX)
|
||||
else if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
|
||||
{
|
||||
int vCount = Vector<double>.Count;
|
||||
int simdEnd = len & ~(vCount - 1);
|
||||
|
||||
for (; i < simdEnd; i += vCount)
|
||||
{
|
||||
// Используем Span для кроссплатформенного создания вектора
|
||||
var v = new Vector<double>(srcDouble.Slice(i, vCount));
|
||||
|
||||
// Кроссплатформенный аппаратный корень (на ARM превратится в NEON инструкцию)
|
||||
var sqrtV = Vector.SquareRoot(v);
|
||||
|
||||
// Копируем напрямую в целевой Span
|
||||
sqrtV.CopyTo(dstDouble.Slice(i, vCount));
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Хвост массива (или обычный расчет, если SIMD на процессоре недоступен)
|
||||
for (; i < len; i++)
|
||||
{
|
||||
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
|
||||
}
|
||||
}
|
||||
internal static void SqrtCore3<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
// Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора
|
||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||
|
||||
int i = 0;
|
||||
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
|
||||
|
||||
// 1. ОСНОВНОЙ ЦИКЛ: Конвейерная обработка по 4 элемента за итерацию
|
||||
for (; i < unrollEnd; i += 4)
|
||||
{
|
||||
T? u0 = Unsafe.Add(ref srcRef, i);
|
||||
T? u1 = Unsafe.Add(ref srcRef, i + 1);
|
||||
T? u2 = Unsafe.Add(ref srcRef, i + 2);
|
||||
T? u3 = Unsafe.Add(ref srcRef, i + 3);
|
||||
|
||||
// Получаем ref-ссылки на целевые ячейки типа R? (zero-cost адресация)
|
||||
ref var d0 = ref Unsafe.Add(ref dstRef, i);
|
||||
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
|
||||
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
|
||||
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
||||
|
||||
// Считаем нативный корень прямо в регистрах и трансформируем тип из T в R по месту
|
||||
d0 = u0.HasValue ? Math.Sqrt(u0.Value.ToDouble()).ToUnit<R>() : null;
|
||||
d1 = u1.HasValue ? Math.Sqrt(u1.Value.ToDouble()).ToUnit<R>() : null;
|
||||
d2 = u2.HasValue ? Math.Sqrt(u2.Value.ToDouble()).ToUnit<R>() : null;
|
||||
d3 = u3.HasValue ? Math.Sqrt(u3.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
||||
for (; i < len; i++)
|
||||
{
|
||||
T? unit = Unsafe.Add(ref srcRef, i);
|
||||
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
||||
dst = unit.HasValue ? Math.Sqrt(unit.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// === ReadOnlySpan ===
|
||||
internal static void Sqrt3<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units.IsEmpty) return;
|
||||
int len = units.Length;
|
||||
if (len > destination.Length)
|
||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||
|
||||
units.SqrtCore3(len, destination);
|
||||
}
|
||||
internal static void Sqrt3<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units.IsEmpty) return;
|
||||
int len = units.Length;
|
||||
if (len > destination.Length)
|
||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||
|
||||
units.SqrtCore3(len, destination);
|
||||
}
|
||||
|
||||
// === Array ===
|
||||
internal static R[] Sqrt3<T, R>(this T[] units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
if (units.Length == 0) return [];
|
||||
|
||||
var result = new R[units.Length];
|
||||
Sqrt3(units, result);
|
||||
return result;
|
||||
}
|
||||
internal static R?[] Sqrt3<T, R>(this T?[] units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
if (units.Length == 0) return [];
|
||||
|
||||
var result = new R?[units.Length];
|
||||
Sqrt3(units, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// === List<Length> ===
|
||||
internal static List<R> Sqrt3<T, R>(this List<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int len = units.Count;
|
||||
if (len == 0) return [];
|
||||
|
||||
var resultArray = new R[len];
|
||||
Sqrt3(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
internal static List<R?> Sqrt3<T, R>(this List<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
int len = units.Count;
|
||||
if (len == 0) return [];
|
||||
|
||||
var resultArray = new R?[len];
|
||||
Sqrt3(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
|
||||
// === ICollection<Length> ===
|
||||
internal static void Sqrt3<T, R>(this ICollection<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Sqrt3(destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (T item in units)
|
||||
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||
}
|
||||
internal static void Sqrt3<T, R>(this ICollection<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Sqrt3(destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (T? item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<Length> ===
|
||||
internal static void Sqrt3<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Sqrt3(destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (T item in units)
|
||||
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||
}
|
||||
internal static void Sqrt3<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
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.Sqrt3(destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (T? item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IEnumerable<Length> + yield ===
|
||||
internal static IEnumerable<R> SqrtIterator3<T, R>(this IEnumerable<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
foreach (var item in units)
|
||||
yield return Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||
}
|
||||
internal static IEnumerable<R?> SqrtNullableIterator3<T, R>(this IEnumerable<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
foreach (var item in units)
|
||||
yield return item.HasValue
|
||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IEnumerable<Length> ===
|
||||
internal static IEnumerable<R> Sqrt3<T, R>(this IEnumerable<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Sqrt3<T, R>();
|
||||
if (units is List<T> list) return list.Sqrt3<T, R>();
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Sqrt3(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
arr.Sqrt3(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
else return SqrtIterator3<T, R>(units);
|
||||
}
|
||||
internal static IEnumerable<R?> Sqrt3<T, R>(this IEnumerable<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Sqrt3<T, R>();
|
||||
if (units is List<T?> list) return list.Sqrt3<T, R>();
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Sqrt3(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
arr.Sqrt3(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
else return SqrtNullableIterator3<T, R>(units);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace QWERTYkez.Mensura;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal class ListLayoutMimic<T>
|
||||
{
|
||||
public T[] Items = null!;
|
||||
public int Size;
|
||||
public int Version;
|
||||
}
|
||||
16
QWERTYkez.Mensura/Mimics.cs
Normal file
16
QWERTYkez.Mensura/Mimics.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace QWERTYkez.Mensura;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal class Mimics<T>
|
||||
{
|
||||
public T[] Items = null!;
|
||||
public int Size;
|
||||
public int Version;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct NullableDoubleMimic
|
||||
{
|
||||
public double Value;
|
||||
public byte HasValue;
|
||||
}
|
||||
@@ -61,21 +61,21 @@ public static class AreaSqrtExtension
|
||||
{
|
||||
// === ReadOnlySpan
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
|
||||
this ReadOnlySpan<Area> units, Span<Length> destination) => units.Sqrt<Area, Length>(destination);
|
||||
this ReadOnlySpan<Area> units, Span<Length> destination) => units.Sqrt3<Area, Length>(destination);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
|
||||
this ReadOnlySpan<Area?> units, Span<Length?> destination) => units.Sqrt<Area, Length>(destination);
|
||||
this ReadOnlySpan<Area?> units, Span<Length?> destination) => units.Sqrt3<Area, Length>(destination);
|
||||
|
||||
// === Array ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static Length[] Sqrt(this Area[] units) => units.Sqrt<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt(this Area?[] units) => units.Sqrt<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static Length[] Sqrt(this Area[] units) => units.Sqrt3<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt(this Area?[] units) => units.Sqrt3<Area, Length>();
|
||||
|
||||
// === List<T> ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt(this List<Area> units) => units.Sqrt<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt(this List<Area?> units) => units.Sqrt<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt(this List<Area> units) => units.Sqrt3<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt(this List<Area?> units) => units.Sqrt3<Area, Length>();
|
||||
|
||||
// === IEnumerable<T> ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt(this IEnumerable<Area> units) => units.Sqrt<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt(this IEnumerable<Area?> units) => units.Sqrt<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt(this IEnumerable<Area> units) => units.Sqrt3<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt(this IEnumerable<Area?> units) => units.Sqrt3<Area, Length>();
|
||||
}
|
||||
|
||||
internal readonly struct AreaConv
|
||||
|
||||
@@ -86,34 +86,30 @@ public readonly partial record struct Length
|
||||
public static class LengthPowExtension
|
||||
{
|
||||
// === ReadOnlySpan
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Pow(
|
||||
this ReadOnlySpan<Length> units, Span<Area> destination) => units.Pow<Length, Area>(destination);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Pow(
|
||||
this ReadOnlySpan<Length?> units, Span<Area?> destination) => units.Pow<Length, Area>(destination);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Pow(
|
||||
this ReadOnlySpan<Length> units, Span<Area> destination) => units.Pow2<Length, Area>(destination);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Pow(
|
||||
this ReadOnlySpan<Length?> units, Span<Area?> destination) => units.Pow2<Length, Area>(destination);
|
||||
|
||||
// === Array ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Area[] Pow(this Length[] units) => units.Pow<Length, Area>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Area?[] Pow(this Length?[] units) => units.Pow<Length, Area>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Area[] Pow(this Length[] units) => units.Pow2<Length, Area>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Area?[] Pow(this Length?[] units) => units.Pow2<Length, Area>();
|
||||
|
||||
// === List<T> ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Area> Pow(this List<Length> units) => units.Pow<Length, Area>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Area?> Pow(this List<Length?> units) => units.Pow<Length, Area>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Area> Pow(this List<Length> units) => units.Pow2<Length, Area>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Area?> Pow(this List<Length?> units) => units.Pow2<Length, Area>();
|
||||
|
||||
// === IEnumerable<T> ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Area> Pow(this IEnumerable<Length> units) => units.Pow<Length, Area>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Area?> Pow(this IEnumerable<Length?> units) => units.Pow<Length, Area>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Area> Pow(this IEnumerable<Length> units) => units.Pow2<Length, Area>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Area?> Pow(this IEnumerable<Length?> units) => units.Pow2<Length, Area>();
|
||||
|
||||
|
||||
|
||||
|
||||
// === ReadOnlySpan
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Pow3(
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Pow3(
|
||||
this ReadOnlySpan<Length> units, Span<Volume> destination) => units.Pow3<Length, Volume>(destination);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Pow3(
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Pow3(
|
||||
this ReadOnlySpan<Length?> units, Span<Volume?> destination) => units.Pow3<Length, Volume>(destination);
|
||||
|
||||
// === Array ===
|
||||
|
||||
@@ -35,29 +35,6 @@ public readonly partial record struct Voltage
|
||||
public Voltage AddMegaVolts(double value) => new(_Value + VoltageConv.MegaVolts.To(value));
|
||||
}
|
||||
|
||||
public static class VolumeSqrtExtension
|
||||
{
|
||||
// === ReadOnlySpan
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Sqrt3(
|
||||
this ReadOnlySpan<Volume> units, Span<Length> destination) => units.Sqrt3<Volume, Length>(destination);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Sqrt3(
|
||||
this ReadOnlySpan<Volume?> units, Span<Length?> destination) => units.Sqrt3<Volume, Length>(destination);
|
||||
|
||||
// === Array ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length[] Sqrt3(this Volume[] units) => units.Sqrt3<Volume, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt3(this Volume?[] units) => units.Sqrt3<Volume, Length>();
|
||||
|
||||
// === List<T> ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt3(this List<Volume> units) => units.Sqrt3<Volume, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt3(this List<Volume?> units) => units.Sqrt3<Volume, Length>();
|
||||
|
||||
// === IEnumerable<T> ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt3(this IEnumerable<Volume> units) => units.Sqrt3<Volume, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt3(this IEnumerable<Volume?> units) => units.Sqrt3<Volume, Length>();
|
||||
}
|
||||
|
||||
internal readonly struct VoltageConv
|
||||
{
|
||||
private VoltageConv(double multiplicator) => this.Multiplicator = multiplicator;
|
||||
|
||||
@@ -35,6 +35,27 @@ public readonly partial record struct Volume
|
||||
public Volume AddMetersCubic(double value) => new(_Value + VolumeConv.MetersCubic.To(value));
|
||||
}
|
||||
|
||||
public static class VolumeSqrtExtension
|
||||
{
|
||||
// === ReadOnlySpan
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt3(
|
||||
this ReadOnlySpan<Volume> units, Span<Length> destination) => units.Sqrt3<Volume, Length>(destination);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt3(
|
||||
this ReadOnlySpan<Volume?> units, Span<Length?> destination) => units.Sqrt3<Volume, Length>(destination);
|
||||
|
||||
// === Array ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length[] Sqrt3(this Volume[] units) => units.Sqrt3<Volume, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt3(this Volume?[] units) => units.Sqrt3<Volume, Length>();
|
||||
|
||||
// === List<T> ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt3(this List<Volume> units) => units.Sqrt3<Volume, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt3(this List<Volume?> units) => units.Sqrt3<Volume, Length>();
|
||||
|
||||
// === IEnumerable<T> ===
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt3(this IEnumerable<Volume> units) => units.Sqrt3<Volume, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt3(this IEnumerable<Volume?> units) => units.Sqrt3<Volume, Length>();
|
||||
}
|
||||
|
||||
internal readonly struct VolumeConv
|
||||
{
|
||||
private VolumeConv(double multiplicator) => this.Multiplicator = multiplicator;
|
||||
|
||||
Reference in New Issue
Block a user