tests
This commit is contained in:
@@ -296,80 +296,6 @@ internal static partial class AggregateUnitExtensions
|
||||
return CollectionsMarshal.AsSpan(list).Min();
|
||||
}
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static T Sum<T>(this ICollection<T> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
if (collection == null || collection.Count == 0) return default;
|
||||
if (collection is T[] array) return array.Sum();
|
||||
if (collection is List<T> list) return list.Sum();
|
||||
|
||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(collection.Count);
|
||||
try
|
||||
{
|
||||
collection.CopyTo(sharedArray, 0); // Встроенный CopyTo работает быстрее, чем ручной foreach
|
||||
return new ReadOnlySpan<T>(sharedArray, 0, collection.Count).Sum();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<T>.Shared.Return(sharedArray);
|
||||
}
|
||||
}
|
||||
internal static T Avg<T>(this ICollection<T> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
if (collection == null || collection.Count == 0) return double.NaN.ToUnit<T>();
|
||||
if (collection is T[] array) return array.Avg();
|
||||
if (collection is List<T> list) return list.Avg();
|
||||
|
||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(collection.Count);
|
||||
try
|
||||
{
|
||||
collection.CopyTo(sharedArray, 0);
|
||||
return new ReadOnlySpan<T>(sharedArray, 0, collection.Count).Avg();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<T>.Shared.Return(sharedArray);
|
||||
}
|
||||
}
|
||||
internal static T Max<T>(this ICollection<T> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
if (collection == null || collection.Count == 0) return double.MinValue.ToUnit<T>();
|
||||
if (collection is T[] array) return array.Max();
|
||||
if (collection is List<T> list) return list.Max();
|
||||
|
||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(collection.Count);
|
||||
try
|
||||
{
|
||||
collection.CopyTo(sharedArray, 0);
|
||||
return new ReadOnlySpan<T>(sharedArray, 0, collection.Count).Max();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<T>.Shared.Return(sharedArray);
|
||||
}
|
||||
}
|
||||
internal static T Min<T>(this ICollection<T> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
if (collection == null || collection.Count == 0) return double.MaxValue.ToUnit<T>();
|
||||
if (collection is T[] array) return array.Min();
|
||||
if (collection is List<T> list) return list.Min();
|
||||
|
||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(collection.Count);
|
||||
try
|
||||
{
|
||||
collection.CopyTo(sharedArray, 0);
|
||||
return new ReadOnlySpan<T>(sharedArray, 0, collection.Count).Min();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<T>.Shared.Return(sharedArray);
|
||||
}
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static T Sum<T>(this IReadOnlyCollection<T> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -446,7 +372,6 @@ internal static partial class AggregateUnitExtensions
|
||||
// Быстрый SIMD-путь для готовых коллекций (0 аллокаций)
|
||||
if (collection is T[] array) return array.Sum();
|
||||
if (collection is List<T> list) return list.Sum();
|
||||
if (collection is ICollection<T> col) return col.Sum();
|
||||
if (collection is IReadOnlyCollection<T> roc) return roc.Sum();
|
||||
|
||||
// Медленный путь для yield return: считаем на лету без буферов
|
||||
@@ -468,7 +393,6 @@ internal static partial class AggregateUnitExtensions
|
||||
|
||||
if (collection is T[] array) return array.Avg();
|
||||
if (collection is List<T> list) return list.Avg();
|
||||
if (collection is ICollection<T> col) return col.Avg();
|
||||
if (collection is IReadOnlyCollection<T> roc) return roc.Avg();
|
||||
|
||||
double sum = 0;
|
||||
@@ -492,7 +416,6 @@ internal static partial class AggregateUnitExtensions
|
||||
|
||||
if (collection is T[] array) return array.Max();
|
||||
if (collection is List<T> list) return list.Max();
|
||||
if (collection is ICollection<T> col) return col.Max();
|
||||
if (collection is IReadOnlyCollection<T> roc) return roc.Max();
|
||||
|
||||
double max = double.MinValue;
|
||||
@@ -514,7 +437,6 @@ internal static partial class AggregateUnitExtensions
|
||||
|
||||
if (collection is T[] array) return array.Min();
|
||||
if (collection is List<T> list) return list.Min();
|
||||
if (collection is ICollection<T> col) return col.Min();
|
||||
if (collection is IReadOnlyCollection<T> roc) return roc.Min();
|
||||
|
||||
double min = double.MaxValue;
|
||||
@@ -708,80 +630,6 @@ internal static partial class AggregateUnitExtensions
|
||||
return CollectionsMarshal.AsSpan(list).Min();
|
||||
}
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static T Sum<T>(this ICollection<T?> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
if (collection == null || collection.Count == 0) return default;
|
||||
if (collection is T?[] array) return array.Sum();
|
||||
if (collection is List<T?> list) return list.Sum();
|
||||
|
||||
T?[] sharedArray = ArrayPool<T?>.Shared.Rent(collection.Count);
|
||||
try
|
||||
{
|
||||
collection.CopyTo(sharedArray, 0);
|
||||
return new ReadOnlySpan<T?>(sharedArray, 0, collection.Count).Sum();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<T?>.Shared.Return(sharedArray);
|
||||
}
|
||||
}
|
||||
internal static T Avg<T>(this ICollection<T?> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
if (collection == null || collection.Count == 0) return double.NaN.ToUnit<T>();
|
||||
if (collection is T?[] array) return array.Avg();
|
||||
if (collection is List<T?> list) return list.Avg();
|
||||
|
||||
T?[] sharedArray = ArrayPool<T?>.Shared.Rent(collection.Count);
|
||||
try
|
||||
{
|
||||
collection.CopyTo(sharedArray, 0);
|
||||
return new ReadOnlySpan<T?>(sharedArray, 0, collection.Count).Avg();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<T?>.Shared.Return(sharedArray);
|
||||
}
|
||||
}
|
||||
internal static T Max<T>(this ICollection<T?> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
if (collection == null || collection.Count == 0) return double.MinValue.ToUnit<T>();
|
||||
if (collection is T?[] array) return array.Max();
|
||||
if (collection is List<T?> list) return list.Max();
|
||||
|
||||
T?[] sharedArray = ArrayPool<T?>.Shared.Rent(collection.Count);
|
||||
try
|
||||
{
|
||||
collection.CopyTo(sharedArray, 0);
|
||||
return new ReadOnlySpan<T?>(sharedArray, 0, collection.Count).Max();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<T?>.Shared.Return(sharedArray);
|
||||
}
|
||||
}
|
||||
internal static T Min<T>(this ICollection<T?> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
if (collection == null || collection.Count == 0) return double.MaxValue.ToUnit<T>();
|
||||
if (collection is T?[] array) return array.Min();
|
||||
if (collection is List<T?> list) return list.Min();
|
||||
|
||||
T?[] sharedArray = ArrayPool<T?>.Shared.Rent(collection.Count);
|
||||
try
|
||||
{
|
||||
collection.CopyTo(sharedArray, 0);
|
||||
return new ReadOnlySpan<T?>(sharedArray, 0, collection.Count).Min();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<T?>.Shared.Return(sharedArray);
|
||||
}
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static T Sum<T>(this IReadOnlyCollection<T?> collection)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -857,7 +705,6 @@ internal static partial class AggregateUnitExtensions
|
||||
// Быстрый SIMD-путь для готовых коллекций за 0 аллокаций
|
||||
if (collection is T?[] array) return array.Sum();
|
||||
if (collection is List<T?> list) return list.Sum();
|
||||
if (collection is ICollection<T?> col) return col.Sum();
|
||||
if (collection is IReadOnlyCollection<T?> roc) return roc.Sum();
|
||||
|
||||
// Медленный путь для ленивого yield return: вычисляем на лету
|
||||
@@ -882,7 +729,6 @@ internal static partial class AggregateUnitExtensions
|
||||
|
||||
if (collection is T?[] array) return array.Avg();
|
||||
if (collection is List<T?> list) return list.Avg();
|
||||
if (collection is ICollection<T?> col) return col.Avg();
|
||||
if (collection is IReadOnlyCollection<T?> roc) return roc.Avg();
|
||||
|
||||
double sum = 0;
|
||||
@@ -909,7 +755,6 @@ internal static partial class AggregateUnitExtensions
|
||||
|
||||
if (collection is T?[] array) return array.Max();
|
||||
if (collection is List<T?> list) return list.Max();
|
||||
if (collection is ICollection<T?> col) return col.Max();
|
||||
if (collection is IReadOnlyCollection<T?> roc) return roc.Max();
|
||||
|
||||
double max = double.MinValue;
|
||||
@@ -934,7 +779,6 @@ internal static partial class AggregateUnitExtensions
|
||||
|
||||
if (collection is T?[] array) return array.Min();
|
||||
if (collection is List<T?> list) return list.Min();
|
||||
if (collection is ICollection<T?> col) return col.Min();
|
||||
if (collection is IReadOnlyCollection<T?> roc) return roc.Min();
|
||||
|
||||
double min = double.MaxValue;
|
||||
|
||||
@@ -1,51 +1,35 @@
|
||||
namespace QWERTYkez.Mensura.Extensions;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace QWERTYkez.Mensura.Extensions;
|
||||
|
||||
internal static partial class CastExtensions
|
||||
{
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static double ToDouble<T>(this T unit)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
return Unsafe.As<T, double>(ref unit);
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static T ToUnit<T>(this double val)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
return Unsafe.As<double, T>(ref val);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void SetCountUnsafe<T>(this List<T> list, int count)
|
||||
{
|
||||
// Берем адрес управляемого объекта List в памяти
|
||||
// Объект передается по ref-ссылке, преобразуется в указатель
|
||||
ref var mimic = ref Unsafe.As<List<T>, Mimics<T>>(ref list);
|
||||
|
||||
// Меняем приватный размер напрямую в памяти объекта!
|
||||
mimic.Size = count;
|
||||
}
|
||||
|
||||
internal static double ToDouble<T>(this T unit) where T : struct, IMensuraUnit, IEquatable<T>
|
||||
=> Unsafe.As<T, double>(ref unit);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T ToUnit<T>(this double val)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => Unsafe.As<double, T>(ref val);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static List<R> WrapAsList<T, R>(this T[] array)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
// Создаём пустой список с нулевой ёмкостью
|
||||
if (array is null) return null!;
|
||||
|
||||
// 1. Физически меняем паспорт (MethodTable) массива на целевой тип R[]
|
||||
object arrObj = array;
|
||||
unsafe { *(nint*)*(nint*)Unsafe.AsPointer(ref arrObj) = typeof(R[]).TypeHandle.Value; }
|
||||
R[] morphedArray = Unsafe.As<R[]>(arrObj);
|
||||
|
||||
// 2. Вшиваем его в новый список
|
||||
var list = new List<R>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<R>, Mimics<T>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
ref var mimic = ref Unsafe.As<List<R>, ListMimic<R>>(ref list);
|
||||
mimic.Items = morphedArray;
|
||||
mimic.Size = array.Length;
|
||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
||||
mimic.Version = 1;
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -55,16 +39,17 @@ internal static partial class CastExtensions
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
// Создаём пустой список с нулевой ёмкостью
|
||||
if (array is null) return null!;
|
||||
|
||||
object arrObj = array;
|
||||
unsafe { *(nint*)*(nint*)Unsafe.AsPointer(ref arrObj) = typeof(R?[]).TypeHandle.Value; }
|
||||
R?[] morphedArray = Unsafe.As<R?[]>(arrObj);
|
||||
|
||||
var list = new List<R?>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<R?>, Mimics<T?>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
ref var mimic = ref Unsafe.As<List<R?>, ListMimic<R?>>(ref list);
|
||||
mimic.Items = morphedArray;
|
||||
mimic.Size = array.Length;
|
||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
||||
mimic.Version = 1;
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -73,16 +58,17 @@ internal static partial class CastExtensions
|
||||
internal static List<double> WrapAsList<T>(this T[] array)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
// Создаём пустой список с нулевой ёмкостью
|
||||
if (array is null) return null!;
|
||||
|
||||
object arrObj = array;
|
||||
unsafe { *(nint*)*(nint*)Unsafe.AsPointer(ref arrObj) = typeof(double[]).TypeHandle.Value; }
|
||||
double[] morphedArray = Unsafe.As<double[]>(arrObj);
|
||||
|
||||
var list = new List<double>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<double>, Mimics<T>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
ref var mimic = ref Unsafe.As<List<double>, ListMimic<double>>(ref list);
|
||||
mimic.Items = morphedArray;
|
||||
mimic.Size = array.Length;
|
||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
||||
mimic.Version = 1;
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -91,16 +77,17 @@ internal static partial class CastExtensions
|
||||
internal static List<double?> WrapAsList<T>(this T?[] array)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
// Создаём пустой список с нулевой ёмкостью
|
||||
if (array is null) return null!;
|
||||
|
||||
object arrObj = array;
|
||||
unsafe { *(nint*)*(nint*)Unsafe.AsPointer(ref arrObj) = typeof(double?[]).TypeHandle.Value; }
|
||||
double?[] morphedArray = Unsafe.As<double?[]>(arrObj);
|
||||
|
||||
var list = new List<double?>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<double?>, Mimics<T?>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
mimic.Items = array;
|
||||
ref var mimic = ref Unsafe.As<List<double?>, ListMimic<double?>>(ref list);
|
||||
mimic.Items = morphedArray;
|
||||
mimic.Size = array.Length;
|
||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
||||
mimic.Version = 1;
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -108,16 +95,14 @@ internal static partial class CastExtensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static List<double> WrapAsList(this double[] array)
|
||||
{
|
||||
// Создаём пустой список с нулевой ёмкостью
|
||||
if (array is null) return null!;
|
||||
|
||||
// Массив уже имеет тип double[], подмена MethodTable не требуется
|
||||
var list = new List<double>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<double>, Mimics<double>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
ref var mimic = ref Unsafe.As<List<double>, ListMimic<double>>(ref list);
|
||||
mimic.Items = array;
|
||||
mimic.Size = array.Length;
|
||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
||||
mimic.Version = 1;
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -125,28 +110,75 @@ internal static partial class CastExtensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static List<double?> WrapAsList(this double?[] array)
|
||||
{
|
||||
// Создаём пустой список с нулевой ёмкостью
|
||||
if (array is null) return null!;
|
||||
|
||||
// Массив уже имеет тип double?[], подмена MethodTable не требуется
|
||||
var list = new List<double?>(0);
|
||||
|
||||
// Получаем внутреннюю структуру списка
|
||||
ref var mimic = ref Unsafe.As<List<double?>, Mimics<double?>>(ref list);
|
||||
|
||||
// Подменяем массив и устанавливаем размер
|
||||
ref var mimic = ref Unsafe.As<List<double?>, ListMimic<double?>>(ref list);
|
||||
mimic.Items = array;
|
||||
mimic.Size = array.Length;
|
||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
||||
mimic.Version = 1;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#region Инфраструктура Нативного Доступа (Zero-Overhead)
|
||||
|
||||
// Генератор сверхбыстрого доступа к приватным полям List<T> через чистый IL.
|
||||
// Работает со скоростью обычного обращения к полю (компилируется в смещение указателя).
|
||||
private static class ListAccessor<T>
|
||||
{
|
||||
public delegate ref T[] GetItemsRefDelegate(List<T> list);
|
||||
public static readonly GetItemsRefDelegate GetItemsRef;
|
||||
|
||||
static ListAccessor()
|
||||
{
|
||||
var field = typeof(List<T>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
?? throw new InvalidOperationException("CLR Layout changed: _items field not found.");
|
||||
|
||||
var dm = new DynamicMethod("GetItemsRef", typeof(T[]).MakeByRefType(), [typeof(List<T>)], typeof(ListAccessor<T>).Module, true);
|
||||
var il = dm.GetILGenerator();
|
||||
il.Emit(OpCodes.Ldarg_0); // Загружаем ссылку на List<T>
|
||||
il.Emit(OpCodes.Ldflda, field); // Получаем управляемый указатель (ref) на поле _items
|
||||
il.Emit(OpCodes.Ret); // Возвращаем его
|
||||
|
||||
GetItemsRef = dm.CreateDelegate<GetItemsRefDelegate>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Реализация ReCast со сменой MethodTable (In-Place Object Morphing)
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static List<R> ReCast<T, R>(this List<T> list)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
return Unsafe.As<List<T>, List<R>>(ref list);
|
||||
if (list is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
// 1. Морфим внутренний массив со скоростью мысли
|
||||
T[] items = ListAccessor<T>.GetItemsRef(list);
|
||||
if (items is not null)
|
||||
{
|
||||
object itemsObj = items;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref itemsObj) = typeof(R[]).TypeHandle.Value;
|
||||
}
|
||||
|
||||
// 2. Морфим сам заголовок List
|
||||
object listObj = list;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref listObj) = typeof(List<R>).TypeHandle.Value;
|
||||
|
||||
return Unsafe.As<List<R>>(listObj);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -154,21 +186,63 @@ internal static partial class CastExtensions
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
return Unsafe.As<List<T?>, List<R?>>(ref list);
|
||||
if (list is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
T?[] items = ListAccessor<T?>.GetItemsRef(list);
|
||||
if (items is not null)
|
||||
{
|
||||
object itemsObj = items;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref itemsObj) = typeof(R?[]).TypeHandle.Value;
|
||||
}
|
||||
|
||||
object listObj = list;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref listObj) = typeof(List<R?>).TypeHandle.Value;
|
||||
|
||||
return Unsafe.As<List<R?>>(listObj);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static List<double> ReCast<T>(this List<T> list)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
return Unsafe.As<List<T>, List<double>>(ref list);
|
||||
if (list is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
T[] items = ListAccessor<T>.GetItemsRef(list);
|
||||
if (items is not null)
|
||||
{
|
||||
object itemsObj = items;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref itemsObj) = typeof(double[]).TypeHandle.Value;
|
||||
}
|
||||
|
||||
object listObj = list;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref listObj) = typeof(List<double>).TypeHandle.Value;
|
||||
|
||||
return Unsafe.As<List<double>>(listObj);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static List<double?> ReCast<T>(this List<T?> list)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
return Unsafe.As<List<T?>, List<double?>>(ref list);
|
||||
if (list is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
T?[] items = ListAccessor<T?>.GetItemsRef(list);
|
||||
if (items is not null)
|
||||
{
|
||||
object itemsObj = items;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref itemsObj) = typeof(double?[]).TypeHandle.Value;
|
||||
}
|
||||
|
||||
object listObj = list;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref listObj) = typeof(List<double?>).TypeHandle.Value;
|
||||
|
||||
return Unsafe.As<List<double?>>(listObj);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -176,7 +250,14 @@ internal static partial class CastExtensions
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
return Unsafe.As<T[], R[]>(ref array);
|
||||
if (array is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
object obj = array;
|
||||
// Ужатие магии: берем адрес переменной на стеке -> читаем адрес объекта в куче -> пишем туда новый MethodTable
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(R[]).TypeHandle.Value;
|
||||
return Unsafe.As<R[]>(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -184,34 +265,66 @@ internal static partial class CastExtensions
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
return Unsafe.As<T?[], R?[]>(ref array);
|
||||
if (array is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
object obj = array;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(R?[]).TypeHandle.Value;
|
||||
return Unsafe.As<R?[]>(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static double[] ReCast<T>(this T[] array)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
return Unsafe.As<T[], double[]>(ref array);
|
||||
if (array is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
object obj = array;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(double[]).TypeHandle.Value;
|
||||
return Unsafe.As<double[]>(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static double?[] ReCast<T>(this T?[] array)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
return Unsafe.As<T?[], double?[]>(ref array);
|
||||
if (array is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
object obj = array;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(double?[]).TypeHandle.Value;
|
||||
return Unsafe.As<double?[]>(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static R[] ReCast<R>(this double[] array)
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
return Unsafe.As<double[], R[]>(ref array);
|
||||
if (array is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
object obj = array;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(R[]).TypeHandle.Value;
|
||||
return Unsafe.As<R[]>(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static R?[] ReCast<R>(this double?[] array)
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
return Unsafe.As<double?[], R?[]>(ref array);
|
||||
if (array is null) return null!;
|
||||
unsafe
|
||||
{
|
||||
object obj = array;
|
||||
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(R?[]).TypeHandle.Value;
|
||||
return Unsafe.As<R?[]>(obj);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -264,80 +264,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Div<T, R>(this ICollection<T> units, double divisor, 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) { DivideCore(array, divisor, count, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).DivideCore(divisor, count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invDivisor = 1.0 / divisor;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item.ToDouble() * invDivisor).ToUnit<R>();
|
||||
}
|
||||
internal static void Div<T, R>(this ICollection<T?> units, double divisor, 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.DivideCore(divisor, count, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).DivideCore(divisor, count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invDivisor = 1.0 / divisor;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
|
||||
}
|
||||
internal static void Div<T, R>(this double dividend, 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) { dividend.DivideCore(array, count, destination); return; }
|
||||
if (units is List<T> list) { dividend.DivideCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (dividend / item.ToDouble()).ToUnit<R>();
|
||||
}
|
||||
internal static void Div<T, R>(this double dividend, 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) { dividend.DivideCore(array, count, destination); return; }
|
||||
if (units is List<T?> list) { dividend.DivideCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (dividend / item.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Div<T, R>(this IReadOnlyCollection<T> units, double divisor, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -454,12 +380,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Div<T, R>(divisor);
|
||||
if (units is List<T> list) return list.Div<T, R>(divisor);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Div(divisor, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -475,12 +395,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Div<T, R>(divisor);
|
||||
if (units is List<T?> list) return list.Div<T, R>(divisor);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Div(divisor, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -496,12 +410,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return dividend.Div<T, R>(array);
|
||||
if (units is List<T> list) return dividend.Div<T, R>(list);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.Div(arr, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -517,12 +425,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return dividend.Div<T, R>(array);
|
||||
if (units is List<T?> list) return dividend.Div<T, R>(list);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.Div(arr, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -670,76 +572,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
return resultArray.WrapAsList<T, T>();
|
||||
}
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Div<T>(this ICollection<T> units, double divisor, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Div(divisor, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invDivisor = 1.0 / divisor;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item.ToDouble() * invDivisor).ToUnit<T>();
|
||||
}
|
||||
internal static void Div<T>(this ICollection<T?> units, double divisor, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Div(divisor, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invDivisor = 1.0 / divisor;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
|
||||
}
|
||||
internal static void Div<T>(this double dividend, ICollection<T> units, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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) { dividend.Div(array, destination); return; }
|
||||
if (units is List<T> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (dividend / item.ToDouble()).ToUnit<T>();
|
||||
}
|
||||
internal static void Div<T>(this double dividend, ICollection<T?> units, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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) { dividend.Div(array, destination); return; }
|
||||
if (units is List<T?> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (dividend / item.Value.ToDouble()).ToUnit<T>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Div<T>(this IReadOnlyCollection<T> units, double divisor, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -847,12 +679,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Div(divisor);
|
||||
if (units is List<T> list) return list.Div(divisor);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Div(divisor, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -867,12 +693,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Div(divisor);
|
||||
if (units is List<T?> list) return list.Div(divisor);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Div(divisor, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -887,12 +707,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return dividend.Div(array);
|
||||
if (units is List<T> list) return dividend.Div(list);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.Div(arr, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -907,12 +721,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return dividend.Div(array);
|
||||
if (units is List<T?> list) return dividend.Div(list);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.Div(arr, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1365,76 +1173,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
return resultArray.WrapAsList<T, T>();
|
||||
}
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Div<T>(this ICollection<double> units, T divisor, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double[] array) { array.Div(divisor, destination); return; }
|
||||
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invDivisor = 1.0 / divisor.ToDouble();
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item * invDivisor).ToUnit<T>();
|
||||
}
|
||||
internal static void Div<T>(this ICollection<double?> units, T divisor, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double?[] array) { array.Div(divisor, destination); return; }
|
||||
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invDivisor = 1.0 / divisor.ToDouble();
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value * invDivisor).ToUnit<T>() : null;
|
||||
}
|
||||
internal static void Div<T>(this T dividend, ICollection<double> units, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double[] array) { dividend.Div(array, destination); return; }
|
||||
if (units is List<double> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (dividend.ToDouble() / item).ToUnit<T>();
|
||||
}
|
||||
internal static void Div<T>(this T dividend, ICollection<double?> units, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double?[] array) { dividend.Div(array, destination); return; }
|
||||
if (units is List<double?> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (dividend.ToDouble() / item.Value).ToUnit<T>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Div<T>(this IReadOnlyCollection<double> units, T divisor, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -1542,12 +1280,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double[] array) return array.Div(divisor);
|
||||
if (units is List<double> list) return list.Div(divisor);
|
||||
if (units is ICollection<double> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.DivCore(divisor.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1562,12 +1294,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double?[] array) return array.Div(divisor);
|
||||
if (units is List<double?> list) return list.Div(divisor);
|
||||
if (units is ICollection<double?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.DivCore(divisor.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1582,12 +1308,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double[] array) return dividend.Div(array);
|
||||
if (units is List<double> list) return dividend.Div(list);
|
||||
if (units is ICollection<double> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.ToDouble().DivCore(arr, arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1602,12 +1322,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double?[] array) return dividend.Div(array);
|
||||
if (units is List<double?> list) return dividend.Div(list);
|
||||
if (units is ICollection<double?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.ToDouble().DivCore(arr, arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1915,76 +1629,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
return resultArray.WrapAsList();
|
||||
}
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Div<T>(this ICollection<T> units, T divisor, Span<double> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Div(divisor, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invDivisor = 1.0 / divisor.ToDouble();
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.ToDouble() * invDivisor;
|
||||
}
|
||||
internal static void Div<T>(this ICollection<T?> units, T divisor, Span<double?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Div(divisor, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invDivisor = 1.0 / divisor.ToDouble();
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue ? item.Value.ToDouble() * invDivisor : null;
|
||||
}
|
||||
internal static void Div<T>(this T dividend, ICollection<T> units, Span<double> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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) { dividend.Div(array, destination); return; }
|
||||
if (units is List<T> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
var div = dividend.ToDouble();
|
||||
foreach (var item in units)
|
||||
destination[i++] = div / item.ToDouble();
|
||||
}
|
||||
internal static void Div<T>(this T dividend, ICollection<T?> units, Span<double?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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) { dividend.Div(array, destination); return; }
|
||||
if (units is List<T?> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
var div = dividend.ToDouble();
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue ? div / item.Value.ToDouble() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Div<T>(this IReadOnlyCollection<T> units, T divisor, Span<double> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -2092,12 +1736,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Div(divisor);
|
||||
if (units is List<T> list) return list.Div(divisor);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -2112,12 +1750,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Div(divisor);
|
||||
if (units is List<T?> list) return list.Div(divisor);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -2132,12 +1764,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return dividend.Div(array);
|
||||
if (units is List<T> list) return dividend.Div(list);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
|
||||
return arr.ReCast();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -2152,12 +1778,6 @@ internal static partial class CollectionsDivideExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return dividend.Div(array);
|
||||
if (units is List<T?> list) return dividend.Div(list);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
|
||||
return arr.ReCast();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
|
||||
@@ -259,78 +259,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Minus<T, R>(this ICollection<T> units, double subtrahend, 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.MinusCore(subtrahend, count, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).MinusCore(subtrahend, count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item.ToDouble() - subtrahend).ToUnit<R>();
|
||||
}
|
||||
internal static void Minus<T, R>(this ICollection<T?> units, double subtrahend, 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.MinusCore(subtrahend, count, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).MinusCore(subtrahend, count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
|
||||
}
|
||||
internal static void Minus<T, R>(this double minuend, 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) { minuend.MinusCore(array, count, destination); return; }
|
||||
if (units is List<T> list) { minuend.MinusCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (minuend - item.ToDouble()).ToUnit<R>();
|
||||
}
|
||||
internal static void Minus<T, R>(this double minuend, 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) { minuend.MinusCore(array, count, destination); return; }
|
||||
if (units is List<T?> list) { minuend.MinusCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (minuend - item.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Minus<T, R>(this IReadOnlyCollection<T> units, double subtrahend, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -443,12 +371,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Minus<T, R>(subtrahend);
|
||||
if (units is List<T> list) return list.Minus<T, R>(subtrahend);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Minus(subtrahend, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -464,12 +386,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Minus<T, R>(subtrahend);
|
||||
if (units is List<T?> list) return list.Minus<T, R>(subtrahend);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Minus(subtrahend, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -485,12 +401,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return minuend.Minus<T, R>(array);
|
||||
if (units is List<T> list) return minuend.Minus<T, R>(list);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
minuend.Minus(arr, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -506,12 +416,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return minuend.Minus<T, R>(array);
|
||||
if (units is List<T?> list) return minuend.Minus<T, R>(list);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
minuend.Minus(arr, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -660,74 +564,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
return resultArray.WrapAsList<T, T>();
|
||||
}
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Minus<T>(this ICollection<T> units, double subtrahend, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Minus(subtrahend, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item.ToDouble() - subtrahend).ToUnit<T>();
|
||||
}
|
||||
internal static void Minus<T>(this ICollection<T?> units, double subtrahend, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Minus(subtrahend, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
|
||||
}
|
||||
internal static void Minus<T>(this double minuend, ICollection<T> units, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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) { minuend.Minus(array, destination); return; }
|
||||
if (units is List<T> list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (minuend - item.ToDouble()).ToUnit<T>();
|
||||
}
|
||||
internal static void Minus<T>(this double minuend, ICollection<T?> units, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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) { minuend.Minus(array, destination); return; }
|
||||
if (units is List<T?> list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (minuend - item.Value.ToDouble()).ToUnit<T>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Minus<T>(this IReadOnlyCollection<T> units, double subtrahend, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -831,12 +667,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Minus(subtrahend);
|
||||
if (units is List<T> list) return list.Minus(subtrahend);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Minus(subtrahend, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -851,12 +681,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Minus(subtrahend);
|
||||
if (units is List<T?> list) return list.Minus(subtrahend);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Minus(subtrahend, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -871,12 +695,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return minuend.Minus(array);
|
||||
if (units is List<T> list) return minuend.Minus(list);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
minuend.Minus(arr, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -891,12 +709,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return minuend.Minus(array);
|
||||
if (units is List<T?> list) return minuend.Minus(list);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
minuend.Minus(arr, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1339,76 +1151,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
return resultArray.WrapAsList<T, T>();
|
||||
}
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Minus<T>(this ICollection<double> units, T divisor, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double[] array) { array.Minus(divisor, destination); return; }
|
||||
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).Minus(divisor, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invMinusisor = 1.0 / divisor.ToDouble();
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item * invMinusisor).ToUnit<T>();
|
||||
}
|
||||
internal static void Minus<T>(this ICollection<double?> units, T divisor, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double?[] array) { array.Minus(divisor, destination); return; }
|
||||
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).Minus(divisor, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
double invMinusisor = 1.0 / divisor.ToDouble();
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value * invMinusisor).ToUnit<T>() : null;
|
||||
}
|
||||
internal static void Minus<T>(this T dividend, ICollection<double> units, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double[] array) { dividend.Minus(array, destination); return; }
|
||||
if (units is List<double> list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (dividend.ToDouble() / item).ToUnit<T>();
|
||||
}
|
||||
internal static void Minus<T>(this T dividend, ICollection<double?> units, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double?[] array) { dividend.Minus(array, destination); return; }
|
||||
if (units is List<double?> list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (dividend.ToDouble() / item.Value).ToUnit<T>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Minus<T>(this IReadOnlyCollection<double> units, T divisor, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -1516,12 +1258,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double[] array) return array.Minus(divisor);
|
||||
if (units is List<double> list) return list.Minus(divisor);
|
||||
if (units is ICollection<double> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1536,12 +1272,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double?[] array) return array.Minus(divisor);
|
||||
if (units is List<double?> list) return list.Minus(divisor);
|
||||
if (units is ICollection<double?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1556,12 +1286,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double[] array) return dividend.Minus(array);
|
||||
if (units is List<double> list) return dividend.Minus(list);
|
||||
if (units is ICollection<double> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1576,12 +1300,6 @@ internal static partial class CollectionsMinusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double?[] array) return dividend.Minus(array);
|
||||
if (units is List<double?> list) return dividend.Minus(list);
|
||||
if (units is ICollection<double?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
|
||||
@@ -162,53 +162,6 @@ internal static partial class CollectionsMultiplyExtensions
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Mul<T, R>(multiplicator);
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Mul<T, R>(this ICollection<T> units, double multiplicator, 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) { MultiplyCore(array, multiplicator, count, destination); return; }
|
||||
if (units is List<T> list) { MultiplyCore(CollectionsMarshal.AsSpan(list), multiplicator, count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item.ToDouble() * multiplicator).ToUnit<R>();
|
||||
}
|
||||
internal static void Mul<T, R>(this ICollection<T?> units, double multiplicator, 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) { MultiplyCore(array, multiplicator, count, destination); return; }
|
||||
if (units is List<T?> list) { MultiplyCore(CollectionsMarshal.AsSpan(list), multiplicator, count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Mul<T, R>(this double multiplicator, ICollection<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Mul(multiplicator, destination);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Mul<T, R>(this double multiplicator, ICollection<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Mul(multiplicator, destination);
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Mul<T, R>(this IReadOnlyCollection<T> units, double multiplicator, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -281,12 +234,6 @@ internal static partial class CollectionsMultiplyExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Mul<T, R>(multiplicator);
|
||||
if (units is List<T> list) return list.Mul<T, R>(multiplicator);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Mul(multiplicator, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -302,12 +249,6 @@ internal static partial class CollectionsMultiplyExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Mul<T, R>(multiplicator);
|
||||
if (units is List<T?> list) return list.Mul<T, R>(multiplicator);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Mul(multiplicator, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -424,49 +365,6 @@ internal static partial class CollectionsMultiplyExtensions
|
||||
internal static List<T?> Mul<T>(this double multiplicator, List<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Mul<T>(this ICollection<T> units, double multiplicator, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Mul(multiplicator, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Mul(multiplicator, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item.ToDouble() * multiplicator).ToUnit<T>();
|
||||
}
|
||||
internal static void Mul<T>(this ICollection<T?> units, double multiplicator, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Mul(multiplicator, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Mul(multiplicator, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Mul<T>(this double multiplicator, ICollection<T> units, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Mul<T>(this double multiplicator, ICollection<T?> units, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Mul<T>(this IReadOnlyCollection<T> units, double multiplicator, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -532,12 +430,6 @@ internal static partial class CollectionsMultiplyExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Mul(multiplicator);
|
||||
if (units is List<T> list) return list.Mul(multiplicator);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Mul(multiplicator, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -552,12 +444,6 @@ internal static partial class CollectionsMultiplyExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Mul(multiplicator);
|
||||
if (units is List<T?> list) return list.Mul(multiplicator);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Mul(multiplicator, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -832,49 +718,6 @@ internal static partial class CollectionsMultiplyExtensions
|
||||
internal static List<T?> Mul<T>(this T multiplicator, List<double?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Mul<T>(this ICollection<double> units, T multiplicator, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double[] array) { array.MultiplyCore(multiplicator.ToDouble(), array.Length, destination); return; }
|
||||
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).MultiplyCore(multiplicator.ToDouble(), list.Count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item * multiplicator.ToDouble()).ToUnit<T>();
|
||||
}
|
||||
internal static void Mul<T>(this ICollection<double?> units, T multiplicator, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double?[] array) { array.MultiplyCore(multiplicator.ToDouble(), array.Length, destination); return; }
|
||||
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).MultiplyCore(multiplicator.ToDouble(), list.Count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value * multiplicator.ToDouble()).ToUnit<T>() : null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Mul<T>(this T multiplicator, ICollection<double> units, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Mul<T>(this T multiplicator, ICollection<double?> units, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Mul<T>(this IReadOnlyCollection<double> units, T multiplicator, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -940,12 +783,6 @@ internal static partial class CollectionsMultiplyExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double[] array) return array.Mul(multiplicator);
|
||||
if (units is List<double> list) return list.Mul(multiplicator);
|
||||
if (units is ICollection<double> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -960,12 +797,6 @@ internal static partial class CollectionsMultiplyExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double?[] array) return array.Mul(multiplicator);
|
||||
if (units is List<double?> list) return list.Mul(multiplicator);
|
||||
if (units is ICollection<double?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
|
||||
@@ -163,53 +163,6 @@ internal static partial class CollectionsPlusExtensions
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Plus<T, R>(summand);
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Plus<T, R>(this ICollection<T> units, double summand, 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) { PlusCore(array, summand, count, destination); return; }
|
||||
if (units is List<T> list) { PlusCore(CollectionsMarshal.AsSpan(list), summand, count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item.ToDouble() + summand).ToUnit<R>();
|
||||
}
|
||||
internal static void Plus<T, R>(this ICollection<T?> units, double summand, 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) { PlusCore(array, summand, count, destination); return; }
|
||||
if (units is List<T?> list) { PlusCore(CollectionsMarshal.AsSpan(list), summand, count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value.ToDouble() + summand).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Plus<T, R>(this double summand, ICollection<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Plus(summand, destination);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Plus<T, R>(this double summand, ICollection<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Plus(summand, destination);
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Plus<T, R>(this IReadOnlyCollection<T> units, double summand, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -282,12 +235,6 @@ internal static partial class CollectionsPlusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Plus<T, R>(summand);
|
||||
if (units is List<T> list) return list.Plus<T, R>(summand);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Plus(summand, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -303,12 +250,6 @@ internal static partial class CollectionsPlusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Plus<T, R>(summand);
|
||||
if (units is List<T?> list) return list.Plus<T, R>(summand);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Plus(summand, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -425,49 +366,6 @@ internal static partial class CollectionsPlusExtensions
|
||||
internal static List<T?> Plus<T>(this double summand, List<T?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Plus<T>(this ICollection<T> units, double summand, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Plus(summand, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item.ToDouble() + summand).ToUnit<T>();
|
||||
}
|
||||
internal static void Plus<T>(this ICollection<T?> units, double summand, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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.Plus(summand, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value.ToDouble() + summand).ToUnit<T>() : null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Plus<T>(this double summand, ICollection<T> units, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Plus<T>(this double summand, ICollection<T?> units, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Plus<T>(this IReadOnlyCollection<T> units, double summand, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -533,12 +431,6 @@ internal static partial class CollectionsPlusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Plus(summand);
|
||||
if (units is List<T> list) return list.Plus(summand);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Plus(summand, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -553,12 +445,6 @@ internal static partial class CollectionsPlusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Plus(summand);
|
||||
if (units is List<T?> list) return list.Plus(summand);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Plus(summand, arr);
|
||||
return arr;
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -837,49 +723,6 @@ internal static partial class CollectionsPlusExtensions
|
||||
internal static List<T?> Plus<T>(this T summand, List<double?> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
||||
|
||||
// === ICollection<T> ===
|
||||
internal static void Plus<T>(this ICollection<double> units, T summand, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double[] array) { array.PlusCore(summand.ToDouble(), array.Length, destination); return; }
|
||||
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = (item + summand.ToDouble()).ToUnit<T>();
|
||||
}
|
||||
internal static void Plus<T>(this ICollection<double?> units, T summand, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
{
|
||||
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 double?[] array) { array.PlusCore(summand.ToDouble(), array.Length, destination); return; }
|
||||
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? (item.Value + summand.ToDouble()).ToUnit<T>() : null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Plus<T>(this T summand, ICollection<double> units, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void Plus<T>(this T summand, ICollection<double?> units, Span<T?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
|
||||
|
||||
// === IReadOnlyCollection<T> ===
|
||||
internal static void Plus<T>(this IReadOnlyCollection<double> units, T summand, Span<T> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -945,12 +788,6 @@ internal static partial class CollectionsPlusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double[] array) return array.Plus(summand);
|
||||
if (units is List<double> list) return list.Plus(summand);
|
||||
if (units is ICollection<double> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.PlusCore(summand.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -965,12 +802,6 @@ internal static partial class CollectionsPlusExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is double?[] array) return array.Plus(summand);
|
||||
if (units is List<double?> list) return list.Plus(summand);
|
||||
if (units is ICollection<double?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.PlusCore(summand.ToDouble(), arr.Length, arr);
|
||||
return arr.ReCast<T>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<double?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
|
||||
@@ -7,8 +7,8 @@ internal static partial class CollectionsPow2Extensions
|
||||
|
||||
// === ВТОРАЯ СТЕПЕНЬ ==========================================
|
||||
|
||||
// === Pow2Core2 === SIMD
|
||||
internal static void Pow2Core2<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||
// === Pow2Core === SIMD
|
||||
internal static void Pow2Core<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
@@ -43,7 +43,7 @@ internal static partial class CollectionsPow2Extensions
|
||||
dstDouble[i] = val * val;
|
||||
}
|
||||
}
|
||||
internal static void Pow2Core2<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||
internal static void Pow2Core<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
@@ -106,7 +106,7 @@ internal static partial class CollectionsPow2Extensions
|
||||
if (len > destination.Length)
|
||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||
|
||||
units.Pow2Core2(len, destination);
|
||||
units.Pow2Core(len, destination);
|
||||
}
|
||||
internal static void Pow2<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -117,7 +117,7 @@ internal static partial class CollectionsPow2Extensions
|
||||
if (len > destination.Length)
|
||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||
|
||||
units.Pow2Core2(len, destination);
|
||||
units.Pow2Core(len, destination);
|
||||
}
|
||||
|
||||
// === Array ===
|
||||
@@ -172,43 +172,6 @@ internal static partial class CollectionsPow2Extensions
|
||||
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>
|
||||
@@ -271,12 +234,6 @@ internal static partial class CollectionsPow2Extensions
|
||||
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();
|
||||
@@ -292,12 +249,6 @@ internal static partial class CollectionsPow2Extensions
|
||||
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();
|
||||
|
||||
@@ -175,43 +175,6 @@ internal static partial class CollectionsPow3Extensions
|
||||
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>
|
||||
@@ -274,12 +237,6 @@ internal static partial class CollectionsPow3Extensions
|
||||
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();
|
||||
@@ -295,12 +252,6 @@ internal static partial class CollectionsPow3Extensions
|
||||
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();
|
||||
|
||||
@@ -222,43 +222,6 @@ internal static partial class CollectionsPowNExtensions
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
|
||||
// === ICollection<Length> ===
|
||||
internal static void Pow<T, R>(this ICollection<T> units, int power, 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.Pow(power, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.ToDouble().QuickPow(power).ToUnit<R>();
|
||||
}
|
||||
internal static void Pow<T, R>(this ICollection<T?> units, int power, 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.Pow(power, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (var item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? item.Value.ToDouble().QuickPow(power).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<Length> ===
|
||||
internal static void Pow<T, R>(this IReadOnlyCollection<T> units, int power, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -321,12 +284,6 @@ internal static partial class CollectionsPowNExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Pow<T, R>(power);
|
||||
if (units is List<T> list) return list.Pow<T, R>(power);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.PowCore(power, arr.Length, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -342,12 +299,6 @@ internal static partial class CollectionsPowNExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Pow<T, R>(power);
|
||||
if (units is List<T?> list) return list.Pow<T, R>(power);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Pow(power, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -534,43 +485,6 @@ internal static partial class CollectionsPowNExtensions
|
||||
return result.WrapAsList<R, R>();
|
||||
}
|
||||
|
||||
// === ICollection<Length> ===
|
||||
internal static void Pow<T, R>(this ICollection<T> units, double power, 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.Pow(power, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (T item in units)
|
||||
destination[i++] = Math.Pow(item.ToDouble(), power).ToUnit<R>();
|
||||
}
|
||||
internal static void Pow<T, R>(this ICollection<T?> units, double power, 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.Pow(power, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (T? item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? Math.Pow(item.Value.ToDouble(), power).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<Length> ===
|
||||
internal static void Pow<T, R>(this IReadOnlyCollection<T> units, double power, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -633,12 +547,6 @@ internal static partial class CollectionsPowNExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Pow<T, R>(power);
|
||||
if (units is List<T> list) return list.Pow<T, R>(power);
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Pow(power, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -654,12 +562,6 @@ internal static partial class CollectionsPowNExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Pow<T, R>(power);
|
||||
if (units is List<T?> list) return list.Pow<T, R>(power);
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Pow(power, arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
|
||||
215
QWERTYkez.Mensura/Extensions/CollectionsRootOfCubeExtensions.cs
Normal file
215
QWERTYkez.Mensura/Extensions/CollectionsRootOfCubeExtensions.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace QWERTYkez.Mensura.Extensions;
|
||||
|
||||
internal static partial class CollectionsRootOfCubeExtensions
|
||||
{
|
||||
// === CbrtCore === SIMD
|
||||
internal static unsafe void CbrtCore<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. SIMD путь (AVX)
|
||||
if (Avx.IsSupported && len >= 4)
|
||||
{
|
||||
int simdEnd = len & ~3;
|
||||
for (; i < simdEnd; i += 4)
|
||||
{
|
||||
double* pSrc = (double*)Unsafe.AsPointer(ref Unsafe.Add(ref srcRef, i));
|
||||
double* pDst = (double*)Unsafe.AsPointer(ref Unsafe.Add(ref dstRef, i));
|
||||
|
||||
// Используем LoadVector256 для максимально быстрой обработки 4-х double
|
||||
Avx.Store(pDst, Avx.Sqrt(Avx.LoadVector256(pSrc)));
|
||||
}
|
||||
}
|
||||
// 2. Fallback путь для остатка
|
||||
for (; i < len; i++)
|
||||
{
|
||||
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
|
||||
}
|
||||
}
|
||||
internal static void CbrtCore<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
{
|
||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||
int i = 0, unrollEnd = len & ~3;
|
||||
|
||||
for (; i < unrollEnd; i += 4)
|
||||
{
|
||||
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||
Unsafe.Add(ref dstRef, i + 1) = Unsafe.Add(ref srcRef, i + 1).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i + 1)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||
Unsafe.Add(ref dstRef, i + 2) = Unsafe.Add(ref srcRef, i + 2).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i + 2)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||
Unsafe.Add(ref dstRef, i + 3) = Unsafe.Add(ref srcRef, i + 3).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i + 3)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
for (; i < len; i++)
|
||||
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === ReadOnlySpan ===
|
||||
internal static void Cbrt<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.CbrtCore(len, destination);
|
||||
}
|
||||
internal static void Cbrt<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.CbrtCore(len, destination);
|
||||
}
|
||||
|
||||
// === Array ===
|
||||
internal static R[] Cbrt<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];
|
||||
Cbrt(units, result);
|
||||
return result;
|
||||
}
|
||||
internal static R?[] Cbrt<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];
|
||||
Cbrt(units, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// === List ===
|
||||
internal static List<R> Cbrt<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];
|
||||
Cbrt(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
internal static List<R?> Cbrt<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];
|
||||
Cbrt(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection ===
|
||||
internal static void Cbrt<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.AsSpan().CbrtCore(count, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).CbrtCore(count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
ref R dstRef = ref MemoryMarshal.GetReference(destination);
|
||||
foreach (T item in units) Unsafe.Add(ref dstRef, i++) = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||
}
|
||||
internal static void Cbrt<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.Cbrt(destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Cbrt(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (T? item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IEnumerable + 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 ===
|
||||
internal static IEnumerable<R> Cbrt<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.Cbrt<T, R>();
|
||||
if (units is List<T> list) return list.Cbrt<T, R>();
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
arr.Cbrt(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
else return SqrtIterator3<T, R>(units);
|
||||
}
|
||||
internal static IEnumerable<R?> Cbrt<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.Cbrt<T, R>();
|
||||
if (units is List<T?> list) return list.Cbrt<T, R>();
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
arr.Cbrt(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
else return SqrtNullableIterator3<T, R>(units);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace QWERTYkez.Mensura.Extensions;
|
||||
|
||||
internal static partial class CollectionsSqrtExtensions
|
||||
internal static partial class CollectionsRootOfSquareExtensions
|
||||
{
|
||||
// === SqrtCore === SIMD
|
||||
internal static unsafe void SqrtCore<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||
@@ -13,11 +13,10 @@ internal static partial class CollectionsSqrtExtensions
|
||||
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
|
||||
// 1. ПУТЬ AVX2 / AVX (x64 Процессоры) — обрабатываем по 4 элемента double за такт
|
||||
if (Avx.IsSupported && len >= 4)
|
||||
{
|
||||
int simdEnd = len & ~3;
|
||||
@@ -26,18 +25,16 @@ internal static partial class CollectionsSqrtExtensions
|
||||
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)
|
||||
// Используем Load вместо LoadVector256 (Load безопасен к невыровненной по 32-байтам памяти)
|
||||
var v = Avx.LoadVector256(pSrc);
|
||||
var sqrtV = Avx.Sqrt(v);
|
||||
// Выровненное сохранение
|
||||
Avx.Store(pDst, sqrtV);
|
||||
}
|
||||
}
|
||||
// 2. ПУТЬ VECTOR (ARM64 / Apple Silicon / Старые CPU без AVX)
|
||||
// 2. КРОССПЛАТФОРМЕННЫЙ VECTOR (ARM64 / Apple Silicon / NEON / SIMD Fallback)
|
||||
else if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
|
||||
{
|
||||
int vCount = Vector<double>.Count;
|
||||
@@ -45,18 +42,13 @@ internal static partial class CollectionsSqrtExtensions
|
||||
|
||||
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 на процессоре недоступен)
|
||||
// 3. ХВОСТ МАССИВА (или работа на старых CPU)
|
||||
for (; i < len; i++)
|
||||
{
|
||||
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
|
||||
@@ -66,47 +58,41 @@ internal static partial class CollectionsSqrtExtensions
|
||||
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)
|
||||
int unrollEnd = len & ~3;
|
||||
|
||||
// 1. ОСНОВНОЙ ЦИКЛ: Конвейерная обработка по 4 элемента за итерацию
|
||||
// ОСНОВНОЙ ЦИКЛ: Конвейерное чтение по 4 элемента (Развертка цикла повышает ILP процессора)
|
||||
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 readonly T? u0 = ref Unsafe.Add(ref srcRef, i);
|
||||
ref readonly T? u1 = ref Unsafe.Add(ref srcRef, i + 1);
|
||||
ref readonly T? u2 = ref Unsafe.Add(ref srcRef, i + 2);
|
||||
ref readonly T? u3 = ref 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 readonly T? unit = ref 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 ===
|
||||
// === ReadOnlySpan API ===
|
||||
internal static void Sqrt<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
@@ -130,7 +116,7 @@ internal static partial class CollectionsSqrtExtensions
|
||||
units.SqrtCore(len, destination);
|
||||
}
|
||||
|
||||
// === Array ===
|
||||
// === Array API ===
|
||||
internal static R[] Sqrt<T, R>(this T[] units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
@@ -139,7 +125,7 @@ internal static partial class CollectionsSqrtExtensions
|
||||
if (units.Length == 0) return [];
|
||||
|
||||
var result = new R[units.Length];
|
||||
Sqrt(units, result);
|
||||
units.AsSpan().SqrtCore(units.Length, result.AsSpan());
|
||||
return result;
|
||||
}
|
||||
internal static R?[] Sqrt<T, R>(this T?[] units)
|
||||
@@ -150,11 +136,11 @@ internal static partial class CollectionsSqrtExtensions
|
||||
if (units.Length == 0) return [];
|
||||
|
||||
var result = new R?[units.Length];
|
||||
Sqrt(units, result);
|
||||
units.AsSpan().SqrtCore(units.Length, result.AsSpan());
|
||||
return result;
|
||||
}
|
||||
|
||||
// === List<Length> ===
|
||||
// === List API ===
|
||||
internal static List<R> Sqrt<T, R>(this List<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
@@ -164,7 +150,7 @@ internal static partial class CollectionsSqrtExtensions
|
||||
if (len == 0) return [];
|
||||
|
||||
var resultArray = new R[len];
|
||||
Sqrt(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
CollectionsMarshal.AsSpan(units).SqrtCore(len, resultArray.AsSpan());
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
internal static List<R?> Sqrt<T, R>(this List<T?> units)
|
||||
@@ -176,48 +162,11 @@ internal static partial class CollectionsSqrtExtensions
|
||||
if (len == 0) return [];
|
||||
|
||||
var resultArray = new R?[len];
|
||||
Sqrt(CollectionsMarshal.AsSpan(units), resultArray);
|
||||
CollectionsMarshal.AsSpan(units).SqrtCore(len, resultArray.AsSpan());
|
||||
return resultArray.WrapAsList<R, R>();
|
||||
}
|
||||
|
||||
// === ICollection<Length> ===
|
||||
internal static void Sqrt<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.Sqrt(destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (T item in units)
|
||||
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||
}
|
||||
internal static void Sqrt<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.Sqrt(destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
||||
|
||||
int i = 0;
|
||||
foreach (T? item in units)
|
||||
destination[i++] = item.HasValue
|
||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IReadOnlyCollection<Length> ===
|
||||
// === IReadOnlyCollection ===
|
||||
internal static void Sqrt<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
@@ -228,12 +177,16 @@ internal static partial class CollectionsSqrtExtensions
|
||||
if (destination.Length < count)
|
||||
throw new ArgumentException("Destination too short");
|
||||
|
||||
if (units is T[] array) { array.Sqrt(destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
||||
if (units is T[] array) { array.AsSpan().SqrtCore(count, destination); return; }
|
||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).SqrtCore(count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
ref R dstRef = ref MemoryMarshal.GetReference(destination);
|
||||
foreach (T item in units)
|
||||
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||
{
|
||||
if ((uint)i >= (uint)count) break;
|
||||
Unsafe.Add(ref dstRef, i++) = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||
}
|
||||
}
|
||||
internal static void Sqrt<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
@@ -245,16 +198,20 @@ internal static partial class CollectionsSqrtExtensions
|
||||
if (destination.Length < count)
|
||||
throw new ArgumentException("Destination too short");
|
||||
|
||||
if (units is T?[] array) { array.Sqrt(destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
||||
if (units is T?[] array) { array.AsSpan().SqrtCore(count, destination); return; }
|
||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).SqrtCore(count, destination); return; }
|
||||
|
||||
int i = 0;
|
||||
ref R? dstRef = ref MemoryMarshal.GetReference(destination);
|
||||
foreach (T? item in units)
|
||||
destination[i++] = item.HasValue
|
||||
{
|
||||
if ((uint)i >= (uint)count) break;
|
||||
Unsafe.Add(ref dstRef, i++) = item.HasValue
|
||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
}
|
||||
|
||||
// === IEnumerable<Length> + yield ===
|
||||
// === IEnumerable Iterators ===
|
||||
internal static IEnumerable<R> SqrtIterator<T, R>(this IEnumerable<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
@@ -271,7 +228,7 @@ internal static partial class CollectionsSqrtExtensions
|
||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||
}
|
||||
|
||||
// === IEnumerable<Length> ===
|
||||
// === IEnumerable API ===
|
||||
internal static IEnumerable<R> Sqrt<T, R>(this IEnumerable<T> units)
|
||||
where T : struct, IMensuraUnit, IEquatable<T>
|
||||
where R : struct, IMensuraUnit, IEquatable<R>
|
||||
@@ -279,12 +236,6 @@ internal static partial class CollectionsSqrtExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T[] array) return array.Sqrt<T, R>();
|
||||
if (units is List<T> list) return list.Sqrt<T, R>();
|
||||
if (units is ICollection<T> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Sqrt(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -300,12 +251,6 @@ internal static partial class CollectionsSqrtExtensions
|
||||
if (units is null) return null!;
|
||||
if (units is T?[] array) return array.Sqrt<T, R>();
|
||||
if (units is List<T?> list) return list.Sqrt<T, R>();
|
||||
if (units is ICollection<T?> col)
|
||||
{
|
||||
var arr = col.ToArray();
|
||||
arr.Sqrt(arr);
|
||||
return arr.ReCast<T, R>();
|
||||
}
|
||||
if (units is IReadOnlyCollection<T?> roc)
|
||||
{
|
||||
var arr = roc.ToArray();
|
||||
@@ -1,317 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,16 @@
|
||||
namespace QWERTYkez.Mensura;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal class Mimics<T>
|
||||
internal class ListMimic<T>
|
||||
{
|
||||
public T[] Items = null!;
|
||||
public int Size;
|
||||
public int Version;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct NullableDoubleMimic
|
||||
[StructLayout(LayoutKind.Explicit, Size = 16)]
|
||||
public struct NullableDoubleMimic
|
||||
{
|
||||
public double Value;
|
||||
public byte HasValue;
|
||||
[FieldOffset(0)] public bool HasValue;
|
||||
[FieldOffset(8)] public double Value;
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn>1701;1702;IDE1006</NoWarn>
|
||||
@@ -13,8 +12,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" PrivateAssets="All" />
|
||||
|
||||
<ProjectReference Include="..\QWERTYkez.Mensura.Generator\QWERTYkez.Mensura.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\QWERTYkez.Mensura.Generator\QWERTYkez.Mensura.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<InternalsVisibleTo Include="QWERTYkez.Mensura.Tests" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -61,21 +61,21 @@ public static class AreaSqrtExtension
|
||||
{
|
||||
// === ReadOnlySpan
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
|
||||
this ReadOnlySpan<Area> units, Span<Length> destination) => units.Sqrt3<Area, Length>(destination);
|
||||
this ReadOnlySpan<Area> units, Span<Length> destination) => units.Cbrt<Area, Length>(destination);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
|
||||
this ReadOnlySpan<Area?> units, Span<Length?> destination) => units.Sqrt3<Area, Length>(destination);
|
||||
this ReadOnlySpan<Area?> units, Span<Length?> destination) => units.Cbrt<Area, Length>(destination);
|
||||
|
||||
// === Array ===
|
||||
[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>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static Length[] Sqrt(this Area[] units) => units.Cbrt<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt(this Area?[] units) => units.Cbrt<Area, Length>();
|
||||
|
||||
// === List<T> ===
|
||||
[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>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt(this List<Area> units) => units.Cbrt<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt(this List<Area?> units) => units.Cbrt<Area, Length>();
|
||||
|
||||
// === IEnumerable<T> ===
|
||||
[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>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt(this IEnumerable<Area> units) => units.Cbrt<Area, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt(this IEnumerable<Area?> units) => units.Cbrt<Area, Length>();
|
||||
}
|
||||
|
||||
internal readonly struct AreaConv
|
||||
|
||||
@@ -38,22 +38,22 @@ public readonly partial record struct Volume
|
||||
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);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Cbrt(
|
||||
this ReadOnlySpan<Volume> units, Span<Length> destination) => units.Cbrt<Volume, Length>(destination);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Cbrt(
|
||||
this ReadOnlySpan<Volume?> units, Span<Length?> destination) => units.Cbrt<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>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length[] Cbrt(this Volume[] units) => units.Cbrt<Volume, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Cbrt(this Volume?[] units) => units.Cbrt<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>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Cbrt(this List<Volume> units) => units.Cbrt<Volume, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Cbrt(this List<Volume?> units) => units.Cbrt<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>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Cbrt(this IEnumerable<Volume> units) => units.Cbrt<Volume, Length>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Cbrt(this IEnumerable<Volume?> units) => units.Cbrt<Volume, Length>();
|
||||
}
|
||||
|
||||
internal readonly struct VolumeConv
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,70 +1,70 @@
|
||||
//#if DEBUG
|
||||
//namespace QWERTYkez.Mensura.Units;
|
||||
#if DEBUG
|
||||
namespace QWERTYkez.Mensura.Units;
|
||||
|
||||
///// <summary>
|
||||
///// Base value is MilliMeters
|
||||
///// </summary>
|
||||
//[DebuggerDisplay("mm = {_MilliMeters.ToString(\"0.###\")}, m = {Meters.ToString(\"0.###\")}")]
|
||||
//public readonly partial record struct XXXXXXXX
|
||||
//{
|
||||
// public static XXXXXXXX MilliMeter { get; } = new(1);
|
||||
// [NotMapped, JsonIgnore, IgnoreDataMember] public double _MilliMeters { get => _Value; init => _Value = value; }
|
||||
/// <summary>
|
||||
/// Base value is MilliMeters
|
||||
/// </summary>
|
||||
[DebuggerDisplay("mm = {_MilliMeters.ToString(\"0.###\")}, m = {Meters.ToString(\"0.###\")}")]
|
||||
public readonly partial record struct XXXXXXXX
|
||||
{
|
||||
public static XXXXXXXX MilliMeter { get; } = new(1);
|
||||
[NotMapped, JsonIgnore, IgnoreDataMember] public double _MilliMeters { get => _Value; init => _Value = value; }
|
||||
|
||||
|
||||
// public static XXXXXXXX CentiMeter { get; } = new(XXXXXXXXConv.CentiMeters.To(1));
|
||||
// [NotMapped, JsonIgnore, IgnoreDataMember]
|
||||
// public double CentiMeters
|
||||
// {
|
||||
// get => XXXXXXXXConv.CentiMeters.From(_Value);
|
||||
// init
|
||||
// {
|
||||
// _Value = XXXXXXXXConv.CentiMeters.To(value);
|
||||
// }
|
||||
// }
|
||||
public static XXXXXXXX CentiMeter { get; } = new(XXXXXXXXConv.CentiMeters.To(1));
|
||||
[NotMapped, JsonIgnore, IgnoreDataMember]
|
||||
public double CentiMeters
|
||||
{
|
||||
get => XXXXXXXXConv.CentiMeters.From(_Value);
|
||||
init
|
||||
{
|
||||
_Value = XXXXXXXXConv.CentiMeters.To(value);
|
||||
}
|
||||
}
|
||||
|
||||
// public static XXXXXXXX DeciMeter { get; } = new(XXXXXXXXConv.DeciMeters.To(1));
|
||||
// [NotMapped, JsonIgnore, IgnoreDataMember]
|
||||
// public double DeciMeters
|
||||
// {
|
||||
// get => XXXXXXXXConv.DeciMeters.From(_Value);
|
||||
// init => _Value = XXXXXXXXConv.DeciMeters.To(value);
|
||||
// }
|
||||
public static XXXXXXXX DeciMeter { get; } = new(XXXXXXXXConv.DeciMeters.To(1));
|
||||
[NotMapped, JsonIgnore, IgnoreDataMember]
|
||||
public double DeciMeters
|
||||
{
|
||||
get => XXXXXXXXConv.DeciMeters.From(_Value);
|
||||
init => _Value = XXXXXXXXConv.DeciMeters.To(value);
|
||||
}
|
||||
|
||||
// public static XXXXXXXX Meter { get; } = new(XXXXXXXXConv.Meters.To(1));
|
||||
// [NotMapped, JsonIgnore, IgnoreDataMember]
|
||||
// public double Meters
|
||||
// {
|
||||
// get => XXXXXXXXConv.Meters.From(_Value);
|
||||
// init => _Value = XXXXXXXXConv.Meters.To(value);
|
||||
// }
|
||||
public static XXXXXXXX Meter { get; } = new(XXXXXXXXConv.Meters.To(1));
|
||||
[NotMapped, JsonIgnore, IgnoreDataMember]
|
||||
public double Meters
|
||||
{
|
||||
get => XXXXXXXXConv.Meters.From(_Value);
|
||||
init => _Value = XXXXXXXXConv.Meters.To(value);
|
||||
}
|
||||
|
||||
// public static XXXXXXXX KiloMeter { get; } = new(XXXXXXXXConv.KiloMeters.To(1));
|
||||
// [NotMapped, JsonIgnore, IgnoreDataMember]
|
||||
// public double KiloMeters
|
||||
// {
|
||||
// get => XXXXXXXXConv.KiloMeters.From(_Value);
|
||||
// init => _Value = XXXXXXXXConv.KiloMeters.To(value);
|
||||
// }
|
||||
public static XXXXXXXX KiloMeter { get; } = new(XXXXXXXXConv.KiloMeters.To(1));
|
||||
[NotMapped, JsonIgnore, IgnoreDataMember]
|
||||
public double KiloMeters
|
||||
{
|
||||
get => XXXXXXXXConv.KiloMeters.From(_Value);
|
||||
init => _Value = XXXXXXXXConv.KiloMeters.To(value);
|
||||
}
|
||||
|
||||
|
||||
// public XXXXXXXX AddMilliMeters(double value) => new(_Value + value);
|
||||
// public XXXXXXXX AddCentiMeters(double value) => new(_Value + XXXXXXXXConv.CentiMeters.To(value));
|
||||
// public XXXXXXXX AddDeciMeters(double value) => new(_Value + XXXXXXXXConv.DeciMeters.To(value));
|
||||
// public XXXXXXXX AddMeters(double value) => new(_Value + XXXXXXXXConv.Meters.To(value));
|
||||
// public XXXXXXXX AddKiloMeters(double value) => new(_Value + XXXXXXXXConv.KiloMeters.To(value));
|
||||
//}
|
||||
public XXXXXXXX AddMilliMeters(double value) => new(_Value + value);
|
||||
public XXXXXXXX AddCentiMeters(double value) => new(_Value + XXXXXXXXConv.CentiMeters.To(value));
|
||||
public XXXXXXXX AddDeciMeters(double value) => new(_Value + XXXXXXXXConv.DeciMeters.To(value));
|
||||
public XXXXXXXX AddMeters(double value) => new(_Value + XXXXXXXXConv.Meters.To(value));
|
||||
public XXXXXXXX AddKiloMeters(double value) => new(_Value + XXXXXXXXConv.KiloMeters.To(value));
|
||||
}
|
||||
|
||||
|
||||
//internal readonly struct XXXXXXXXConv
|
||||
//{
|
||||
// private XXXXXXXXConv(double multiplicator) => this.Multiplicator = multiplicator;
|
||||
// public double To(double value) => value * Multiplicator;
|
||||
// public double From(double value) => value / Multiplicator;
|
||||
// public double Multiplicator { get; init; }
|
||||
// public static XXXXXXXXConv MilliMeters { get; } = new(1);
|
||||
// public static XXXXXXXXConv CentiMeters { get; } = new(10);
|
||||
// public static XXXXXXXXConv DeciMeters { get; } = new(100);
|
||||
// public static XXXXXXXXConv Meters { get; } = new(1000);
|
||||
// public static XXXXXXXXConv KiloMeters { get; } = new(1000000);
|
||||
//}
|
||||
//#endif
|
||||
internal readonly struct XXXXXXXXConv
|
||||
{
|
||||
private XXXXXXXXConv(double multiplicator) => this.Multiplicator = multiplicator;
|
||||
public double To(double value) => value * Multiplicator;
|
||||
public double From(double value) => value / Multiplicator;
|
||||
public double Multiplicator { get; init; }
|
||||
public static XXXXXXXXConv MilliMeters { get; } = new(1);
|
||||
public static XXXXXXXXConv CentiMeters { get; } = new(10);
|
||||
public static XXXXXXXXConv DeciMeters { get; } = new(100);
|
||||
public static XXXXXXXXConv Meters { get; } = new(1000);
|
||||
public static XXXXXXXXConv KiloMeters { get; } = new(1000000);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user