26.06.03
This commit is contained in:
@@ -91,7 +91,9 @@ namespace QWERTYkez.Mensura
|
|||||||
// Вы должны скопировать сюда всё содержимое вашего второго файла,
|
// Вы должны скопировать сюда всё содержимое вашего второго файла,
|
||||||
// заменив {typeName} на {typeName}.
|
// заменив {typeName} на {typeName}.
|
||||||
string skeleton = @"
|
string skeleton = @"
|
||||||
|
global using {typeName}Extensions = QWERTYkez.Mensura.Units.{typeName}Extensions;
|
||||||
global using {typeName} = QWERTYkez.Mensura.Units.{typeName};
|
global using {typeName} = QWERTYkez.Mensura.Units.{typeName};
|
||||||
|
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Units;
|
namespace QWERTYkez.Mensura.Units;
|
||||||
@@ -131,14 +133,13 @@ public readonly partial record struct {typeName} : IMensuraUnit<{typeName}>, IEq
|
|||||||
public static {typeName} NegativeInfinity { get; } = new(double.NegativeInfinity);
|
public static {typeName} NegativeInfinity { get; } = new(double.NegativeInfinity);
|
||||||
public static {typeName} PositiveInfinity { get; } = new(double.PositiveInfinity);
|
public static {typeName} PositiveInfinity { get; } = new(double.PositiveInfinity);
|
||||||
|
|
||||||
|
public static bool operator ==({typeName}? T1, {typeName}? T2) => T1.Protected() == T2.Protected();
|
||||||
|
public static bool operator !=({typeName}? T1, {typeName}? T2) => T1.Protected() != T2.Protected();
|
||||||
|
|
||||||
public static bool operator ==({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) == (T2 is null ? 0d : T2.Value._Value);
|
public static bool operator <({typeName}? T1, {typeName}? T2) => T1.Protected() < T2.Protected();
|
||||||
public static bool operator !=({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) != (T2 is null ? 0d : T2.Value._Value);
|
public static bool operator <=({typeName}? T1, {typeName}? T2) => T1.Protected() <= T2.Protected();
|
||||||
|
public static bool operator >({typeName}? T1, {typeName}? T2) => T1.Protected() > T2.Protected();
|
||||||
public static bool operator <({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) < (T2 is null ? 0d : T2.Value._Value);
|
public static bool operator >=({typeName}? T1, {typeName}? T2) => T1.Protected() >= T2.Protected();
|
||||||
public static bool operator <=({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) <= (T2 is null ? 0d : T2.Value._Value);
|
|
||||||
public static bool operator >({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) > (T2 is null ? 0d : T2.Value._Value);
|
|
||||||
public static bool operator >=({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) >= (T2 is null ? 0d : T2.Value._Value);
|
|
||||||
|
|
||||||
|
|
||||||
public static {typeName} operator +({typeName} T2) => new(+T2._Value);
|
public static {typeName} operator +({typeName} T2) => new(+T2._Value);
|
||||||
@@ -283,6 +284,11 @@ public readonly partial record struct {typeName} : IMensuraUnit<{typeName}>, IEq
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal R Sqrt_Internal<R>() where R : struct, IMensuraUnit, IEquatable<R> => Math.Sqrt(_Value).ToUnit<R>();
|
internal R Sqrt_Internal<R>() where R : struct, IMensuraUnit, IEquatable<R> => Math.Sqrt(_Value).ToUnit<R>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class {typeName}Extensions
|
||||||
|
{
|
||||||
|
public static double Protected(this {typeName}? unit) => unit is null ? 0d : unit.Value._Value;
|
||||||
|
}
|
||||||
";
|
";
|
||||||
return skeleton.Replace("{typeName}", typeName).Replace("{ns}", ns);
|
return skeleton.Replace("{typeName}", typeName).Replace("{ns}", ns);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,15 +11,6 @@ public static partial class CastExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static double ToDouble<T>(this T? unit)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
T actual = unit.GetValueOrDefault();
|
|
||||||
return Unsafe.As<T, double>(ref actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static T ToUnit<T>(this double val)
|
internal static T ToUnit<T>(this double val)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
|||||||
@@ -1,20 +1,14 @@
|
|||||||
using System.Buffers;
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Extensions;
|
|
||||||
|
|
||||||
public static partial class CollectionsDivideExtensions
|
public static partial class CollectionsDivideExtensions
|
||||||
{
|
{
|
||||||
// === ReadOnlySpan === SIMD
|
// === DivideCore === SIMD
|
||||||
public static void Divide<T>(this ReadOnlySpan<T> units, double divisor, Span<T> destination)
|
internal static void DivideCore<T, R>(this ReadOnlySpan<T> units, double divisor, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
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.");
|
|
||||||
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<T, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
// Вместо деления в цикле, умножаем на обратное число (invDivisor)
|
// Вместо деления в цикле, умножаем на обратное число (invDivisor)
|
||||||
double invDivisor = 1.0 / divisor;
|
double invDivisor = 1.0 / divisor;
|
||||||
@@ -46,15 +40,10 @@ public static partial class CollectionsDivideExtensions
|
|||||||
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * invDivisor;
|
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * invDivisor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Divide<T>(this ReadOnlySpan<T?> units, double divisor, Span<T?> destination)
|
internal static void DivideCore<T, R>(this ReadOnlySpan<T?> units, double divisor, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
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.");
|
|
||||||
|
|
||||||
|
|
||||||
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
@@ -78,10 +67,10 @@ public static partial class CollectionsDivideExtensions
|
|||||||
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
||||||
|
|
||||||
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
||||||
d0 = u0.HasValue ? (u0.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
|
d0 = u0.HasValue ? (u0.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
|
||||||
d1 = u1.HasValue ? (u1.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
|
d1 = u1.HasValue ? (u1.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
|
||||||
d2 = u2.HasValue ? (u2.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
|
d2 = u2.HasValue ? (u2.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
|
||||||
d3 = u3.HasValue ? (u3.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
|
d3 = u3.HasValue ? (u3.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
||||||
@@ -90,20 +79,16 @@ public static partial class CollectionsDivideExtensions
|
|||||||
T? unit = Unsafe.Add(ref srcRef, i);
|
T? unit = Unsafe.Add(ref srcRef, i);
|
||||||
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
||||||
|
|
||||||
dst = unit.HasValue ? (unit.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
|
dst = unit.HasValue ? (unit.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//SIMD
|
//SIMD
|
||||||
public static void Divide<T>(this double dividend, ReadOnlySpan<T> units, Span<T> destination)
|
internal static void DivideCore<T, R>(this double dividend, ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
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.");
|
|
||||||
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<T, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
var vectorizedDividend = new Vector<double>(dividend);
|
var vectorizedDividend = new Vector<double>(dividend);
|
||||||
int vectorSize = Vector<double>.Count;
|
int vectorSize = Vector<double>.Count;
|
||||||
@@ -133,13 +118,10 @@ public static partial class CollectionsDivideExtensions
|
|||||||
Unsafe.Add(ref dstRef, i) = dividend / Unsafe.Add(ref srcRef, i);
|
Unsafe.Add(ref dstRef, i) = dividend / Unsafe.Add(ref srcRef, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Divide<T>(this double dividend, ReadOnlySpan<T?> units, Span<T?> destination)
|
internal static void DivideCore<T, R>(this double dividend, ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units.IsEmpty) return;
|
|
||||||
|
|
||||||
int len = units.Length;
|
|
||||||
|
|
||||||
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
@@ -162,10 +144,10 @@ public static partial class CollectionsDivideExtensions
|
|||||||
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
||||||
|
|
||||||
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
||||||
d0 = u0.HasValue ? (dividend / u0.Value.ToDouble()).ToUnit<T>() : null;
|
d0 = u0.HasValue ? (dividend / u0.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
d1 = u1.HasValue ? (dividend / u1.Value.ToDouble()).ToUnit<T>() : null;
|
d1 = u1.HasValue ? (dividend / u1.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
d2 = u2.HasValue ? (dividend / u2.Value.ToDouble()).ToUnit<T>() : null;
|
d2 = u2.HasValue ? (dividend / u2.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
d3 = u3.HasValue ? (dividend / u3.Value.ToDouble()).ToUnit<T>() : null;
|
d3 = u3.HasValue ? (dividend / u3.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
||||||
@@ -174,10 +156,56 @@ public static partial class CollectionsDivideExtensions
|
|||||||
T? unit = Unsafe.Add(ref srcRef, i);
|
T? unit = Unsafe.Add(ref srcRef, i);
|
||||||
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
||||||
|
|
||||||
dst = unit.HasValue ? (dividend / unit.Value.ToDouble()).ToUnit<T>() : null;
|
dst = unit.HasValue ? (dividend / unit.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// === ReadOnlySpan
|
||||||
|
public static void Divide<T>(this ReadOnlySpan<T> units, double divisor, Span<T> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.DivideCore(divisor, len, destination);
|
||||||
|
}
|
||||||
|
public static void Divide<T>(this ReadOnlySpan<T?> units, double divisor, Span<T?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.DivideCore(divisor, len, destination);
|
||||||
|
}
|
||||||
|
public static void Divide<T>(this double dividend, ReadOnlySpan<T> units, Span<T> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
dividend.DivideCore(units, len, destination);
|
||||||
|
}
|
||||||
|
public static void Divide<T>(this double dividend, ReadOnlySpan<T?> units, Span<T?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
dividend.DivideCore(units, len, destination);
|
||||||
|
}
|
||||||
|
|
||||||
// === Array ===
|
// === Array ===
|
||||||
public static T[] Divide<T>(this T[] units, double divisor)
|
public static T[] Divide<T>(this T[] units, double divisor)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -197,21 +225,8 @@ public static partial class CollectionsDivideExtensions
|
|||||||
int len = units.Length;
|
int len = units.Length;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
// Выделяем чистую память (0 аллокаций логики, только сам массив)
|
|
||||||
var result = new T?[len];
|
var result = new T?[len];
|
||||||
double invDivisor = 1.0 / divisor;
|
Divide(units, divisor, result);
|
||||||
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
// Читаем из исходного по значению (бесплатно для 8 байт)
|
|
||||||
T? item = units[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
// Пишем напрямую в результат по ref-ссылке (всего 1 запись в память!)
|
|
||||||
ref var dst = ref result[i];
|
|
||||||
dst = (item.Value.ToDouble() * invDivisor).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static T[] Divide<T>(this double dividend, T[] units)
|
public static T[] Divide<T>(this double dividend, T[] units)
|
||||||
@@ -233,16 +248,7 @@ public static partial class CollectionsDivideExtensions
|
|||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
var result = new T?[len];
|
var result = new T?[len];
|
||||||
|
Divide(dividend, units, result);
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
T? item = units[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref result[i];
|
|
||||||
dst = (dividend / item.Value.ToDouble()).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,27 +272,17 @@ public static partial class CollectionsDivideExtensions
|
|||||||
if (count == 0) return [];
|
if (count == 0) return [];
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
var resultArray = new T?[count];
|
||||||
double invDivisor = 1.0 / divisor;
|
Divide(CollectionsMarshal.AsSpan(units), divisor, resultArray);
|
||||||
ReadOnlySpan<T?> srcSpan = CollectionsMarshal.AsSpan(units);
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
T? item = srcSpan[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (item.Value.ToDouble() * invDivisor).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
public static List<T> Divide<T>(this double dividend, List<T> units)
|
public static List<T> Divide<T>(this double dividend, List<T> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
int len = units.Count;
|
int count = units.Count;
|
||||||
if (len == 0) return [];
|
if (count == 0) return [];
|
||||||
|
|
||||||
var resultArray = new T[len];
|
var resultArray = new T[count];
|
||||||
Divide(dividend, CollectionsMarshal.AsSpan(units), resultArray);
|
Divide(dividend, CollectionsMarshal.AsSpan(units), resultArray);
|
||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
@@ -298,220 +294,148 @@ public static partial class CollectionsDivideExtensions
|
|||||||
if (count == 0) return [];
|
if (count == 0) return [];
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
var resultArray = new T?[count];
|
||||||
ReadOnlySpan<T?> srcSpan = CollectionsMarshal.AsSpan(units);
|
Divide(dividend, CollectionsMarshal.AsSpan(units), resultArray);
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
T? item = srcSpan[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (dividend / item.Value.ToDouble()).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
// === ICollection<T> ===
|
||||||
public static ICollection<T> Divide<T>(this ICollection<T> units, double divisor)
|
public static void Divide<T>(this ICollection<T> units, double divisor, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Divide(divisor);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Divide(divisor);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { array.Divide(divisor, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Divide(divisor, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedArray, 0);
|
double invDivisor = 1.0 / divisor;
|
||||||
Divide(new ReadOnlySpan<T>(sharedArray, 0, count), divisor, finalResult.AsSpan());
|
foreach (var item in units)
|
||||||
return finalResult;
|
destination[i++] = (item.ToDouble() * invDivisor).ToUnit<T>();
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static ICollection<T?> Divide<T>(this ICollection<T?> units, double divisor)
|
public static void Divide<T>(this ICollection<T?> units, double divisor, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Divide(divisor);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Divide(divisor);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
if (units is T?[] array) { array.Divide(divisor, destination); return; }
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Divide(divisor, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedNullableArray, 0);
|
double invDivisor = 1.0 / divisor;
|
||||||
var srcSpan = new ReadOnlySpan<T?>(sharedNullableArray, 0, count);
|
foreach (var item in units)
|
||||||
srcSpan.Divide(divisor, resultArray);
|
destination[i++] = item.HasValue
|
||||||
return resultArray;
|
? (item.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static ICollection<T> Divide<T>(this double dividend, ICollection<T> units)
|
public static void Divide<T>(this double dividend, ICollection<T> units, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return dividend.Divide(array);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return dividend.Divide(list);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { dividend.Divide(array, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { dividend.Divide(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedArray, 0);
|
foreach (var item in units)
|
||||||
Divide(dividend, new ReadOnlySpan<T>(sharedArray, 0, count), finalResult.AsSpan());
|
destination[i++] = (dividend / item.ToDouble()).ToUnit<T>();
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static ICollection<T?> Divide<T>(this double dividend, ICollection<T?> units)
|
public static void Divide<T>(this double dividend, ICollection<T?> units, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return dividend.Divide(array);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return dividend.Divide(list);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
if (units is T?[] array) { dividend.Divide(array, destination); return; }
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is List<T?> list) { dividend.Divide(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedNullableArray, 0);
|
foreach (var item in units)
|
||||||
var srcSpan = new ReadOnlySpan<T?>(sharedNullableArray, 0, count);
|
destination[i++] = item.HasValue
|
||||||
dividend.Divide(srcSpan, resultArray);
|
? (dividend / item.Value.ToDouble()).ToUnit<T>() : null;
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
public static IReadOnlyCollection<T> Divide<T>(this IReadOnlyCollection<T> units, double divisor)
|
public static void Divide<T>(this IReadOnlyCollection<T> units, double divisor, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Divide(divisor);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Divide(divisor);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { array.Divide(divisor, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Divide(divisor, destination); return; }
|
||||||
try
|
|
||||||
{
|
|
||||||
int index = 0;
|
|
||||||
foreach (var item in units) sharedArray[index++] = item;
|
|
||||||
Divide(sharedArray, divisor, finalResult.AsSpan());
|
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static IReadOnlyCollection<T?> Divide<T>(this IReadOnlyCollection<T?> units, double divisor)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return null!;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return [];
|
|
||||||
if (units is T?[] array) return array.Divide(divisor);
|
|
||||||
if (units is List<T?> list) return list.Divide(divisor);
|
|
||||||
|
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
int i = 0;
|
||||||
var resultArray = new T?[count];
|
|
||||||
double invDivisor = 1.0 / divisor;
|
double invDivisor = 1.0 / divisor;
|
||||||
try
|
foreach (var item in units)
|
||||||
{
|
destination[i++] = (item.ToDouble() * invDivisor).ToUnit<T>();
|
||||||
int index = 0;
|
|
||||||
foreach (var item in units) sharedNullableArray[index++] = item;
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
T? item = sharedNullableArray[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (item.Value.ToDouble() * invDivisor).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static IReadOnlyCollection<T> Divide<T>(this double dividend, IReadOnlyCollection<T> units)
|
public static void Divide<T>(this IReadOnlyCollection<T?> units, double divisor, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Divide(dividend);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Divide(dividend);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T?[] array) { array.Divide(divisor, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Divide(divisor, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
double invDivisor = 1.0 / divisor;
|
||||||
foreach (var item in units) sharedArray[index++] = item;
|
foreach (var item in units)
|
||||||
Divide(dividend, sharedArray, finalResult.AsSpan());
|
destination[i++] = item.HasValue
|
||||||
return finalResult;
|
? (item.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static IReadOnlyCollection<T?> Divide<T>(this double dividend, IReadOnlyCollection<T?> units)
|
public static void Divide<T>(this double dividend, IReadOnlyCollection<T> units, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Divide(dividend);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Divide(dividend);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is T[] array) { dividend.Divide(array, destination); return; }
|
||||||
var resultArray = new T?[count];
|
if (units is List<T> list) { dividend.Divide(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
foreach (var item in units)
|
||||||
foreach (var item in units) sharedNullableArray[index++] = item;
|
destination[i++] = (dividend / item.ToDouble()).ToUnit<T>();
|
||||||
for (int i = 0; i < count; i++)
|
}
|
||||||
{
|
public static void Divide<T>(this double dividend, IReadOnlyCollection<T?> units, Span<T?> destination)
|
||||||
T? item = sharedNullableArray[i];
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
if (item.HasValue)
|
{
|
||||||
{
|
if (units is null) return;
|
||||||
ref var dst = ref resultArray[i];
|
int count = units.Count;
|
||||||
dst = (dividend / item.Value.ToDouble()).ToUnit<T>();
|
if (count == 0) return;
|
||||||
}
|
if (destination.Length < count)
|
||||||
}
|
throw new ArgumentException("Destination too short");
|
||||||
return resultArray;
|
|
||||||
}
|
if (units is T?[] array) { dividend.Divide(array, destination); return; }
|
||||||
finally
|
if (units is List<T?> list) { dividend.Divide(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
int i = 0;
|
||||||
}
|
foreach (var item in units)
|
||||||
|
destination[i++] = item.HasValue
|
||||||
|
? (dividend / item.Value.ToDouble()).ToUnit<T>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IEnumerable<T> + yeild ===
|
// === IEnumerable<T> + yeild ===
|
||||||
@@ -551,8 +475,18 @@ public static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Divide(divisor);
|
if (units is T[] array) return array.Divide(divisor);
|
||||||
if (units is List<T> list) return list.Divide(divisor);
|
if (units is List<T> list) return list.Divide(divisor);
|
||||||
if (units is ICollection<T> col) return col.Divide(divisor);
|
if (units is ICollection<T> col)
|
||||||
if (units is IReadOnlyCollection<T> roc) return roc.Divide(divisor);
|
{
|
||||||
|
var arr = new T[col.Count];
|
||||||
|
col.Divide(divisor, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = new T[roc.Count];
|
||||||
|
roc.Divide(divisor, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return DivideIterator(units, divisor);
|
return DivideIterator(units, divisor);
|
||||||
}
|
}
|
||||||
public static IEnumerable<T?> Divide<T>(this IEnumerable<T?> units, double divisor)
|
public static IEnumerable<T?> Divide<T>(this IEnumerable<T?> units, double divisor)
|
||||||
@@ -561,8 +495,18 @@ public static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Divide(divisor);
|
if (units is T?[] array) return array.Divide(divisor);
|
||||||
if (units is List<T?> list) return list.Divide(divisor);
|
if (units is List<T?> list) return list.Divide(divisor);
|
||||||
if (units is ICollection<T?> col) return col.Divide(divisor);
|
if (units is ICollection<T?> col)
|
||||||
if (units is IReadOnlyCollection<T?> roc) return roc.Divide(divisor);
|
{
|
||||||
|
var arr = new T?[col.Count];
|
||||||
|
col.Divide(divisor, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = new T?[roc.Count];
|
||||||
|
roc.Divide(divisor, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return DivideNullableIterator(units, divisor);
|
return DivideNullableIterator(units, divisor);
|
||||||
}
|
}
|
||||||
public static IEnumerable<T> Divide<T>(this double dividend, IEnumerable<T> units)
|
public static IEnumerable<T> Divide<T>(this double dividend, IEnumerable<T> units)
|
||||||
@@ -571,8 +515,18 @@ public static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return dividend.Divide(array);
|
if (units is T[] array) return dividend.Divide(array);
|
||||||
if (units is List<T> list) return dividend.Divide(list);
|
if (units is List<T> list) return dividend.Divide(list);
|
||||||
if (units is ICollection<T> col) return dividend.Divide(col);
|
if (units is ICollection<T> col)
|
||||||
if (units is IReadOnlyCollection<T> roc) return dividend.Divide(roc);
|
{
|
||||||
|
var arr = new T[col.Count];
|
||||||
|
dividend.Divide(col, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = new T[roc.Count];
|
||||||
|
dividend.Divide(roc, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return DivideIterator(dividend, units);
|
return DivideIterator(dividend, units);
|
||||||
}
|
}
|
||||||
public static IEnumerable<T?> Divide<T>(this double dividend, IEnumerable<T?> units)
|
public static IEnumerable<T?> Divide<T>(this double dividend, IEnumerable<T?> units)
|
||||||
@@ -581,8 +535,18 @@ public static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return dividend.Divide(array);
|
if (units is T?[] array) return dividend.Divide(array);
|
||||||
if (units is List<T?> list) return dividend.Divide(list);
|
if (units is List<T?> list) return dividend.Divide(list);
|
||||||
if (units is ICollection<T?> col) return dividend.Divide(col);
|
if (units is ICollection<T?> col)
|
||||||
if (units is IReadOnlyCollection<T?> roc) return dividend.Divide(roc);
|
{
|
||||||
|
var arr = new T?[col.Count];
|
||||||
|
dividend.Divide(col, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = new T?[roc.Count];
|
||||||
|
dividend.Divide(roc, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return DivideNullableIterator(dividend, units);
|
return DivideNullableIterator(dividend, units);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,14 @@
|
|||||||
using System.Buffers;
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Extensions;
|
|
||||||
|
|
||||||
public static partial class CollectionsMinusExtensions
|
public static partial class CollectionsMinusExtensions
|
||||||
{
|
{
|
||||||
// === ReadOnlySpan === SIMD
|
// === MinusCore === SIMD
|
||||||
public static void Minus<T>(this ReadOnlySpan<T> units, double subtrahend, Span<T> destination)
|
internal static void MinusCore<T, R>(this ReadOnlySpan<T> units, double subtrahend, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
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.");
|
|
||||||
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<T, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
var vectorizedSubtrahend = new Vector<double>(subtrahend);
|
var vectorizedSubtrahend = new Vector<double>(subtrahend);
|
||||||
int vectorSize = Vector<double>.Count;
|
int vectorSize = Vector<double>.Count;
|
||||||
@@ -42,13 +36,10 @@ public static partial class CollectionsMinusExtensions
|
|||||||
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend;
|
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Minus<T>(this ReadOnlySpan<T?> units, double subtrahend, Span<T?> destination)
|
internal static void MinusCore<T, R>(this ReadOnlySpan<T?> units, double subtrahend, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units.IsEmpty) return;
|
|
||||||
|
|
||||||
int len = units.Length;
|
|
||||||
|
|
||||||
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
@@ -71,10 +62,10 @@ public static partial class CollectionsMinusExtensions
|
|||||||
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
||||||
|
|
||||||
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
||||||
d0 = u0.HasValue ? (u0.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
|
d0 = u0.HasValue ? (u0.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
|
||||||
d1 = u1.HasValue ? (u1.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
|
d1 = u1.HasValue ? (u1.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
|
||||||
d2 = u2.HasValue ? (u2.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
|
d2 = u2.HasValue ? (u2.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
|
||||||
d3 = u3.HasValue ? (u3.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
|
d3 = u3.HasValue ? (u3.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
||||||
@@ -83,20 +74,16 @@ public static partial class CollectionsMinusExtensions
|
|||||||
T? unit = Unsafe.Add(ref srcRef, i);
|
T? unit = Unsafe.Add(ref srcRef, i);
|
||||||
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
||||||
|
|
||||||
dst = unit.HasValue ? (unit.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
|
dst = unit.HasValue ? (unit.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//SIMD
|
//SIMD
|
||||||
public static void Minus<T>(this double minuend, ReadOnlySpan<T> units, Span<T> destination)
|
internal static void MinusCore<T, R>(this double minuend, ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
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.");
|
|
||||||
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<T, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
var vectorizedMinuend = new Vector<double>(minuend);
|
var vectorizedMinuend = new Vector<double>(minuend);
|
||||||
int vectorSize = Vector<double>.Count;
|
int vectorSize = Vector<double>.Count;
|
||||||
@@ -126,13 +113,10 @@ public static partial class CollectionsMinusExtensions
|
|||||||
Unsafe.Add(ref dstRef, i) = minuend - Unsafe.Add(ref srcRef, i);
|
Unsafe.Add(ref dstRef, i) = minuend - Unsafe.Add(ref srcRef, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Minus<T>(this double minuend, ReadOnlySpan<T?> units, Span<T?> destination)
|
internal static void MinusCore<T, R>(this double minuend, ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units.IsEmpty) return;
|
|
||||||
|
|
||||||
int len = units.Length;
|
|
||||||
|
|
||||||
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
@@ -155,10 +139,10 @@ public static partial class CollectionsMinusExtensions
|
|||||||
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
||||||
|
|
||||||
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
||||||
d0 = u0.HasValue ? (minuend - u0.Value.ToDouble()).ToUnit<T>() : null;
|
d0 = u0.HasValue ? (minuend - u0.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
d1 = u1.HasValue ? (minuend - u1.Value.ToDouble()).ToUnit<T>() : null;
|
d1 = u1.HasValue ? (minuend - u1.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
d2 = u2.HasValue ? (minuend - u2.Value.ToDouble()).ToUnit<T>() : null;
|
d2 = u2.HasValue ? (minuend - u2.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
d3 = u3.HasValue ? (minuend - u3.Value.ToDouble()).ToUnit<T>() : null;
|
d3 = u3.HasValue ? (minuend - u3.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
||||||
@@ -167,10 +151,57 @@ public static partial class CollectionsMinusExtensions
|
|||||||
T? unit = Unsafe.Add(ref srcRef, i);
|
T? unit = Unsafe.Add(ref srcRef, i);
|
||||||
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
||||||
|
|
||||||
dst = unit.HasValue ? (minuend - unit.Value.ToDouble()).ToUnit<T>() : null;
|
dst = unit.HasValue ? (minuend - unit.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// === ReadOnlySpan
|
||||||
|
public static void Minus<T>(this ReadOnlySpan<T> units, double subtrahend, Span<T> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.MinusCore(subtrahend, len, destination);
|
||||||
|
}
|
||||||
|
public static void Minus<T>(this ReadOnlySpan<T?> units, double subtrahend, Span<T?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.MinusCore(subtrahend, len, destination);
|
||||||
|
}
|
||||||
|
//SIMD
|
||||||
|
public static void Minus<T>(this double minuend, ReadOnlySpan<T> units, Span<T> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
minuend.MinusCore(units, len, destination);
|
||||||
|
}
|
||||||
|
public static void Minus<T>(this double minuend, ReadOnlySpan<T?> units, Span<T?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
minuend.MinusCore(units, len, destination);
|
||||||
|
}
|
||||||
|
|
||||||
// === Array ===
|
// === Array ===
|
||||||
public static T[] Minus<T>(this T[] units, double subtrahend)
|
public static T[] Minus<T>(this T[] units, double subtrahend)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -190,19 +221,8 @@ public static partial class CollectionsMinusExtensions
|
|||||||
int len = units.Length;
|
int len = units.Length;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
// Выделяем чистую память (0 аллокаций логики, только сам массив)
|
|
||||||
var result = new T?[len];
|
var result = new T?[len];
|
||||||
for (int i = 0; i < len; i++)
|
Minus(units, subtrahend, result);
|
||||||
{
|
|
||||||
// Читаем из исходного по значению (бесплатно для 8 байт)
|
|
||||||
T? item = units[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
// Пишем напрямую в результат по ref-ссылке (всего 1 запись в память!)
|
|
||||||
ref var dst = ref result[i];
|
|
||||||
dst = (item.Value.ToDouble() - subtrahend).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static T[] Minus<T>(this double minuend, T[] units)
|
public static T[] Minus<T>(this double minuend, T[] units)
|
||||||
@@ -224,16 +244,7 @@ public static partial class CollectionsMinusExtensions
|
|||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
var result = new T?[len];
|
var result = new T?[len];
|
||||||
|
Minus(minuend, units, result);
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
T? item = units[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref result[i];
|
|
||||||
dst = (minuend - item.Value.ToDouble()).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,26 +268,17 @@ public static partial class CollectionsMinusExtensions
|
|||||||
if (count == 0) return [];
|
if (count == 0) return [];
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
var resultArray = new T?[count];
|
||||||
ReadOnlySpan<T?> srcSpan = CollectionsMarshal.AsSpan(units);
|
Minus(CollectionsMarshal.AsSpan(units), subtrahend, resultArray);
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
T? item = srcSpan[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (item.Value.ToDouble() - subtrahend).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
public static List<T> Minus<T>(this double minuend, List<T> units)
|
public static List<T> Minus<T>(this double minuend, List<T> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
int len = units.Count;
|
int count = units.Count;
|
||||||
if (len == 0) return [];
|
if (count == 0) return [];
|
||||||
|
|
||||||
var resultArray = new T[len];
|
var resultArray = new T[count];
|
||||||
Minus(minuend, CollectionsMarshal.AsSpan(units), resultArray);
|
Minus(minuend, CollectionsMarshal.AsSpan(units), resultArray);
|
||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
@@ -288,219 +290,144 @@ public static partial class CollectionsMinusExtensions
|
|||||||
if (count == 0) return [];
|
if (count == 0) return [];
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
var resultArray = new T?[count];
|
||||||
ReadOnlySpan<T?> srcSpan = CollectionsMarshal.AsSpan(units);
|
Minus(minuend, CollectionsMarshal.AsSpan(units), resultArray);
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
T? item = srcSpan[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (minuend - item.Value.ToDouble()).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
// === ICollection<T> ===
|
||||||
public static ICollection<T> Minus<T>(this ICollection<T> units, double subtrahend)
|
public static void Minus<T>(this ICollection<T> units, double subtrahend, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Minus(subtrahend);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Minus(subtrahend);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { array.Minus(subtrahend, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedArray, 0);
|
foreach (var item in units)
|
||||||
Minus(new ReadOnlySpan<T>(sharedArray, 0, count), subtrahend, finalResult.AsSpan());
|
destination[i++] = (item.ToDouble() - subtrahend).ToUnit<T>();
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static ICollection<T?> Minus<T>(this ICollection<T?> units, double subtrahend)
|
public static void Minus<T>(this ICollection<T?> units, double subtrahend, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Minus(subtrahend);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Minus(subtrahend);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
if (units is T?[] array) { array.Minus(subtrahend, destination); return; }
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedNullableArray, 0);
|
foreach (var item in units)
|
||||||
var srcSpan = new ReadOnlySpan<T?>(sharedNullableArray, 0, count);
|
destination[i++] = item.HasValue
|
||||||
srcSpan.Minus(subtrahend, resultArray);
|
? (item.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static ICollection<T> Minus<T>(this double minuend, ICollection<T> units)
|
public static void Minus<T>(this double minuend, ICollection<T> units, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return minuend.Minus(array);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return minuend.Minus(list);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { minuend.Minus(array, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedArray, 0);
|
foreach (var item in units)
|
||||||
Minus(minuend, new ReadOnlySpan<T>(sharedArray, 0, count), finalResult.AsSpan());
|
destination[i++] = (minuend - item.ToDouble()).ToUnit<T>();
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static ICollection<T?> Minus<T>(this double minuend, ICollection<T?> units)
|
public static void Minus<T>(this double minuend, ICollection<T?> units, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return minuend.Minus(array);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return minuend.Minus(list);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
if (units is T?[] array) { minuend.Minus(array, destination); return; }
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is List<T?> list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedNullableArray, 0);
|
foreach (var item in units)
|
||||||
var srcSpan = new ReadOnlySpan<T?>(sharedNullableArray, 0, count);
|
destination[i++] = item.HasValue
|
||||||
minuend.Minus(srcSpan, resultArray);
|
? (minuend - item.Value.ToDouble()).ToUnit<T>() : null;
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
public static IReadOnlyCollection<T> Minus<T>(this IReadOnlyCollection<T> units, double subtrahend)
|
public static void Minus<T>(this IReadOnlyCollection<T> units, double subtrahend, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Minus(subtrahend);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Minus(subtrahend);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { array.Minus(subtrahend, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
foreach (var item in units)
|
||||||
foreach (var item in units) sharedArray[index++] = item;
|
destination[i++] = (item.ToDouble() - subtrahend).ToUnit<T>();
|
||||||
Minus(sharedArray, subtrahend, finalResult.AsSpan());
|
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static IReadOnlyCollection<T?> Minus<T>(this IReadOnlyCollection<T?> units, double subtrahend)
|
public static void Minus<T>(this IReadOnlyCollection<T?> units, double subtrahend, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Minus(subtrahend);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Minus(subtrahend);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is T?[] array) { array.Minus(subtrahend, destination); return; }
|
||||||
var resultArray = new T?[count];
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
foreach (var item in units)
|
||||||
foreach (var item in units) sharedNullableArray[index++] = item;
|
destination[i++] = item.HasValue
|
||||||
for (int i = 0; i < count; i++)
|
? (item.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
|
||||||
{
|
|
||||||
T? item = sharedNullableArray[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (item.Value.ToDouble() - subtrahend).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static IReadOnlyCollection<T> Minus<T>(this double minuend, IReadOnlyCollection<T> units)
|
public static void Minus<T>(this double minuend, IReadOnlyCollection<T> units, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Minus(minuend);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Minus(minuend);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { minuend.Minus(array, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
foreach (var item in units)
|
||||||
foreach (var item in units) sharedArray[index++] = item;
|
destination[i++] = (minuend - item.ToDouble()).ToUnit<T>();
|
||||||
Minus(minuend, sharedArray, finalResult.AsSpan());
|
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static IReadOnlyCollection<T?> Minus<T>(this double minuend, IReadOnlyCollection<T?> units)
|
public static void Minus<T>(this double minuend, IReadOnlyCollection<T?> units, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Minus(minuend);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Minus(minuend);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is T?[] array) { minuend.Minus(array, destination); return; }
|
||||||
var resultArray = new T?[count];
|
if (units is List<T?> list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
foreach (var item in units)
|
||||||
foreach (var item in units) sharedNullableArray[index++] = item;
|
destination[i++] = item.HasValue
|
||||||
for (int i = 0; i < count; i++)
|
? (minuend - item.Value.ToDouble()).ToUnit<T>() : null;
|
||||||
{
|
|
||||||
T? item = sharedNullableArray[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (minuend - item.Value.ToDouble()).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IEnumerable<T> + yeild ===
|
// === IEnumerable<T> + yeild ===
|
||||||
@@ -538,8 +465,18 @@ public static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Minus(subtrahend);
|
if (units is T[] array) return array.Minus(subtrahend);
|
||||||
if (units is List<T> list) return list.Minus(subtrahend);
|
if (units is List<T> list) return list.Minus(subtrahend);
|
||||||
if (units is ICollection<T> col) return col.Minus(subtrahend);
|
if (units is ICollection<T> col)
|
||||||
if (units is IReadOnlyCollection<T> roc) return roc.Minus(subtrahend);
|
{
|
||||||
|
var arr = new T[col.Count];
|
||||||
|
col.Minus(subtrahend, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = new T[roc.Count];
|
||||||
|
roc.Minus(subtrahend, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return MinusIterator(units, subtrahend);
|
return MinusIterator(units, subtrahend);
|
||||||
}
|
}
|
||||||
public static IEnumerable<T?> Minus<T>(this IEnumerable<T?> units, double subtrahend)
|
public static IEnumerable<T?> Minus<T>(this IEnumerable<T?> units, double subtrahend)
|
||||||
@@ -548,8 +485,18 @@ public static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Minus(subtrahend);
|
if (units is T?[] array) return array.Minus(subtrahend);
|
||||||
if (units is List<T?> list) return list.Minus(subtrahend);
|
if (units is List<T?> list) return list.Minus(subtrahend);
|
||||||
if (units is ICollection<T?> col) return col.Minus(subtrahend);
|
if (units is ICollection<T?> col)
|
||||||
if (units is IReadOnlyCollection<T?> roc) return roc.Minus(subtrahend);
|
{
|
||||||
|
var arr = new T?[col.Count];
|
||||||
|
col.Minus(subtrahend, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = new T?[roc.Count];
|
||||||
|
roc.Minus(subtrahend, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return MinusNullableIterator(units, subtrahend);
|
return MinusNullableIterator(units, subtrahend);
|
||||||
}
|
}
|
||||||
public static IEnumerable<T> Minus<T>(this double minuend, IEnumerable<T> units)
|
public static IEnumerable<T> Minus<T>(this double minuend, IEnumerable<T> units)
|
||||||
@@ -558,8 +505,18 @@ public static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return minuend.Minus(array);
|
if (units is T[] array) return minuend.Minus(array);
|
||||||
if (units is List<T> list) return minuend.Minus(list);
|
if (units is List<T> list) return minuend.Minus(list);
|
||||||
if (units is ICollection<T> col) return minuend.Minus(col);
|
if (units is ICollection<T> col)
|
||||||
if (units is IReadOnlyCollection<T> roc) return minuend.Minus(roc);
|
{
|
||||||
|
var arr = new T[col.Count];
|
||||||
|
minuend.Minus(col, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = new T[roc.Count];
|
||||||
|
minuend.Minus(roc, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return MinusIterator(minuend, units);
|
return MinusIterator(minuend, units);
|
||||||
}
|
}
|
||||||
public static IEnumerable<T?> Minus<T>(this double minuend, IEnumerable<T?> units)
|
public static IEnumerable<T?> Minus<T>(this double minuend, IEnumerable<T?> units)
|
||||||
@@ -568,8 +525,18 @@ public static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return minuend.Minus(array);
|
if (units is T?[] array) return minuend.Minus(array);
|
||||||
if (units is List<T?> list) return minuend.Minus(list);
|
if (units is List<T?> list) return minuend.Minus(list);
|
||||||
if (units is ICollection<T?> col) return minuend.Minus(col);
|
if (units is ICollection<T?> col)
|
||||||
if (units is IReadOnlyCollection<T?> roc) return minuend.Minus(roc);
|
{
|
||||||
|
var arr = new T?[col.Count];
|
||||||
|
minuend.Minus(col, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = new T?[roc.Count];
|
||||||
|
minuend.Minus(roc, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return MinusNullableIterator(minuend, units);
|
return MinusNullableIterator(minuend, units);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,14 @@
|
|||||||
using System.Buffers;
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Extensions;
|
|
||||||
|
|
||||||
public static partial class CollectionsMultiplyExtensions
|
public static partial class CollectionsMultiplyExtensions
|
||||||
{
|
{
|
||||||
// === ReadOnlySpan === SIMD
|
// === MultiplyCore === SIMD
|
||||||
public static void Multiply<T>(this ReadOnlySpan<T> units, double multiplicator, Span<T> destination)
|
internal static void MultiplyCore<T, R>(this ReadOnlySpan<T> units, double multiplicator, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
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.");
|
|
||||||
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<T, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
var vectorizedMultiplicator = new Vector<double>(multiplicator);
|
var vectorizedMultiplicator = new Vector<double>(multiplicator);
|
||||||
int vectorSize = Vector<double>.Count;
|
int vectorSize = Vector<double>.Count;
|
||||||
@@ -41,14 +35,10 @@ public static partial class CollectionsMultiplyExtensions
|
|||||||
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator;
|
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Multiply<T>(this ReadOnlySpan<T?> units, double multiplicator, Span<T?> destination)
|
internal static void MultiplyCore<T, R>(this ReadOnlySpan<T?> units, double multiplicator, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
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.");
|
|
||||||
|
|
||||||
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
@@ -71,10 +61,10 @@ public static partial class CollectionsMultiplyExtensions
|
|||||||
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
||||||
|
|
||||||
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
||||||
d0 = u0.HasValue ? (u0.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
|
d0 = u0.HasValue ? (u0.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
|
||||||
d1 = u1.HasValue ? (u1.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
|
d1 = u1.HasValue ? (u1.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
|
||||||
d2 = u2.HasValue ? (u2.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
|
d2 = u2.HasValue ? (u2.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
|
||||||
d3 = u3.HasValue ? (u3.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
|
d3 = u3.HasValue ? (u3.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
||||||
@@ -83,10 +73,45 @@ public static partial class CollectionsMultiplyExtensions
|
|||||||
T? unit = Unsafe.Add(ref srcRef, i);
|
T? unit = Unsafe.Add(ref srcRef, i);
|
||||||
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
||||||
|
|
||||||
dst = unit.HasValue ? (unit.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
|
dst = unit.HasValue ? (unit.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static void MultiplyCore<T, R>(this double multiplicator, ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R> => units.MultiplyCore(multiplicator, len, destination);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static void MultiplyCore<T, R>(this double multiplicator, ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R> => units.MultiplyCore(multiplicator, len, destination);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// === ReadOnlySpan
|
||||||
|
public static void Multiply<T>(this ReadOnlySpan<T> units, double multiplicator, Span<T> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.MultiplyCore(multiplicator, len, destination);
|
||||||
|
}
|
||||||
|
public static void Multiply<T>(this ReadOnlySpan<T?> units, double multiplicator, Span<T?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.MultiplyCore(multiplicator, len, destination);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Multiply<T>(this double multiplicator, ReadOnlySpan<T> units, Span<T> destination)
|
public static void Multiply<T>(this double multiplicator, ReadOnlySpan<T> units, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator, destination);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator, destination);
|
||||||
@@ -114,20 +139,8 @@ public static partial class CollectionsMultiplyExtensions
|
|||||||
int len = units.Length;
|
int len = units.Length;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
// Выделяем чистую память (0 аллокаций логики, только сам массив)
|
|
||||||
var result = new T?[len];
|
var result = new T?[len];
|
||||||
|
Multiply(units, multiplicator, result);
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
// Читаем из исходного по значению (бесплатно для 8 байт)
|
|
||||||
T? item = units[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
// Пишем напрямую в результат по ref-ссылке (всего 1 запись в память!)
|
|
||||||
ref var dst = ref result[i];
|
|
||||||
dst = (item.Value.ToDouble() * multiplicator).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,16 +172,7 @@ public static partial class CollectionsMultiplyExtensions
|
|||||||
if (count == 0) return [];
|
if (count == 0) return [];
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
var resultArray = new T?[count];
|
||||||
ReadOnlySpan<T?> srcSpan = CollectionsMarshal.AsSpan(units);
|
Multiply(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
T? item = srcSpan[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (item.Value.ToDouble() * multiplicator).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,123 +185,90 @@ public static partial class CollectionsMultiplyExtensions
|
|||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
// === ICollection<T> ===
|
||||||
public static ICollection<T> Multiply<T>(this ICollection<T> units, double multiplicator)
|
public static void Multiply<T>(this ICollection<T> units, double multiplicator, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Multiply(multiplicator);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Multiply(multiplicator);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { array.Multiply(multiplicator, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedArray, 0);
|
foreach (var item in units)
|
||||||
Multiply(new ReadOnlySpan<T>(sharedArray, 0, count), multiplicator, finalResult.AsSpan());
|
destination[i++] = (item.ToDouble() * multiplicator).ToUnit<T>();
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static ICollection<T?> Multiply<T>(this ICollection<T?> units, double multiplicator)
|
public static void Multiply<T>(this ICollection<T?> units, double multiplicator, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Multiply(multiplicator);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Multiply(multiplicator);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
if (units is T?[] array) { array.Multiply(multiplicator, destination); return; }
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedNullableArray, 0);
|
foreach (var item in units)
|
||||||
var srcSpan = new ReadOnlySpan<T?>(sharedNullableArray, 0, count);
|
destination[i++] = item.HasValue
|
||||||
srcSpan.Multiply(multiplicator, resultArray);
|
? (item.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ICollection<T> Multiply<T>(this double multiplicator, ICollection<T> units)
|
public static void Multiply<T>(this double multiplicator, ICollection<T> units, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator, destination);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ICollection<T?> Multiply<T>(this double multiplicator, ICollection<T?> units)
|
public static void Multiply<T>(this double multiplicator, ICollection<T?> units, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator, destination);
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
public static IReadOnlyCollection<T> Multiply<T>(this IReadOnlyCollection<T> units, double multiplicator)
|
public static void Multiply<T>(this IReadOnlyCollection<T> units, double multiplicator, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Multiply(multiplicator);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Multiply(multiplicator);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { array.Multiply(multiplicator, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
foreach (var item in units)
|
||||||
foreach (var item in units) sharedArray[index++] = item;
|
destination[i++] = (item.ToDouble() * multiplicator).ToUnit<T>();
|
||||||
Multiply(sharedArray, multiplicator, finalResult.AsSpan());
|
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static IReadOnlyCollection<T?> Multiply<T>(this IReadOnlyCollection<T?> units, double multiplicator)
|
public static void Multiply<T>(this IReadOnlyCollection<T?> units, double multiplicator, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Multiply(multiplicator);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Multiply(multiplicator);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is T?[] array) { array.Multiply(multiplicator, destination); return; }
|
||||||
var resultArray = new T?[count];
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
foreach (var item in units)
|
||||||
foreach (var item in units) sharedNullableArray[index++] = item;
|
destination[i++] = item.HasValue
|
||||||
for (int i = 0; i < count; i++)
|
? (item.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
|
||||||
{
|
|
||||||
T? item = sharedNullableArray[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (item.Value.ToDouble() * multiplicator).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static IReadOnlyCollection<T> Multiply<T>(this double multiplicator, IReadOnlyCollection<T> units)
|
public static void Multiply<T>(this double multiplicator, IReadOnlyCollection<T> units, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator, destination);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static IReadOnlyCollection<T?> Multiply<T>(this double multiplicator, IReadOnlyCollection<T?> units)
|
public static void Multiply<T>(this double multiplicator, IReadOnlyCollection<T?> units, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Multiply(multiplicator, destination);
|
||||||
|
|
||||||
// === IEnumerable<T> + yeild ===
|
// === IEnumerable<T> + yeild ===
|
||||||
static IEnumerable<T> MultiplyIterator<T>(IEnumerable<T> units, double multiplicator)
|
static IEnumerable<T> MultiplyIterator<T>(IEnumerable<T> units, double multiplicator)
|
||||||
@@ -321,8 +292,18 @@ public static partial class CollectionsMultiplyExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Multiply(multiplicator);
|
if (units is T[] array) return array.Multiply(multiplicator);
|
||||||
if (units is List<T> list) return list.Multiply(multiplicator);
|
if (units is List<T> list) return list.Multiply(multiplicator);
|
||||||
if (units is ICollection<T> col) return col.Multiply(multiplicator);
|
if (units is ICollection<T> col)
|
||||||
if (units is IReadOnlyCollection<T> roc) return roc.Multiply(multiplicator);
|
{
|
||||||
|
var arr = new T[col.Count];
|
||||||
|
col.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = new T[roc.Count];
|
||||||
|
roc.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return MultiplyIterator(units, multiplicator);
|
return MultiplyIterator(units, multiplicator);
|
||||||
}
|
}
|
||||||
public static IEnumerable<T?> Multiply<T>(this IEnumerable<T?> units, double multiplicator)
|
public static IEnumerable<T?> Multiply<T>(this IEnumerable<T?> units, double multiplicator)
|
||||||
@@ -331,8 +312,18 @@ public static partial class CollectionsMultiplyExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Multiply(multiplicator);
|
if (units is T?[] array) return array.Multiply(multiplicator);
|
||||||
if (units is List<T?> list) return list.Multiply(multiplicator);
|
if (units is List<T?> list) return list.Multiply(multiplicator);
|
||||||
if (units is ICollection<T?> col) return col.Multiply(multiplicator);
|
if (units is ICollection<T?> col)
|
||||||
if (units is IReadOnlyCollection<T?> roc) return roc.Multiply(multiplicator);
|
{
|
||||||
|
var arr = new T?[col.Count];
|
||||||
|
col.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = new T?[roc.Count];
|
||||||
|
roc.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return MultiplyNullableIterator(units, multiplicator);
|
return MultiplyNullableIterator(units, multiplicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,14 @@
|
|||||||
using System.Buffers;
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Extensions;
|
|
||||||
|
|
||||||
public static partial class CollectionsPlusExtensions
|
public static partial class CollectionsPlusExtensions
|
||||||
{
|
{
|
||||||
// === ReadOnlySpan === SIMD
|
// === ReadOnlySpan === SIMD
|
||||||
public static void Plus<T>(this ReadOnlySpan<T> units, double summand, Span<T> destination)
|
internal static void PlusCore<T, R>(this ReadOnlySpan<T> units, double summand, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
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.");
|
|
||||||
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<T, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
var vectorizedSummand = new Vector<double>(summand);
|
var vectorizedSummand = new Vector<double>(summand);
|
||||||
int vectorSize = Vector<double>.Count;
|
int vectorSize = Vector<double>.Count;
|
||||||
@@ -42,13 +36,10 @@ public static partial class CollectionsPlusExtensions
|
|||||||
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand;
|
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Plus<T>(this ReadOnlySpan<T?> units, double summand, Span<T?> destination)
|
internal static void PlusCore<T, R>(this ReadOnlySpan<T?> units, double summand, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units.IsEmpty) return;
|
|
||||||
|
|
||||||
int len = units.Length;
|
|
||||||
|
|
||||||
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
@@ -71,10 +62,10 @@ public static partial class CollectionsPlusExtensions
|
|||||||
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
||||||
|
|
||||||
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
|
||||||
d0 = u0.HasValue ? (u0.Value.ToDouble() + summand).ToUnit<T>() : null;
|
d0 = u0.HasValue ? (u0.Value.ToDouble() + summand).ToUnit<R>() : null;
|
||||||
d1 = u1.HasValue ? (u1.Value.ToDouble() + summand).ToUnit<T>() : null;
|
d1 = u1.HasValue ? (u1.Value.ToDouble() + summand).ToUnit<R>() : null;
|
||||||
d2 = u2.HasValue ? (u2.Value.ToDouble() + summand).ToUnit<T>() : null;
|
d2 = u2.HasValue ? (u2.Value.ToDouble() + summand).ToUnit<R>() : null;
|
||||||
d3 = u3.HasValue ? (u3.Value.ToDouble() + summand).ToUnit<T>() : null;
|
d3 = u3.HasValue ? (u3.Value.ToDouble() + summand).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
||||||
@@ -83,17 +74,52 @@ public static partial class CollectionsPlusExtensions
|
|||||||
T? unit = Unsafe.Add(ref srcRef, i);
|
T? unit = Unsafe.Add(ref srcRef, i);
|
||||||
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
||||||
|
|
||||||
dst = unit.HasValue ? (unit.Value.ToDouble() + summand).ToUnit<T>() : null;
|
dst = unit.HasValue ? (unit.Value.ToDouble() + summand).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Plus<T>(this double summand, ReadOnlySpan<T> units, Span<T> destination)
|
internal static void PlusCore<T, R>(this double summand, ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R> => units.PlusCore(summand, len, destination);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Plus<T>(this double summand, ReadOnlySpan<T?> units, Span<T?> destination)
|
internal static void PlusCore<T, R>(this double summand, ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R> => units.PlusCore(summand, len, destination);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// === ReadOnlySpan
|
||||||
|
public static void Plus<T>(this ReadOnlySpan<T> units, double multiplicator, Span<T> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.PlusCore(multiplicator, len, destination);
|
||||||
|
}
|
||||||
|
public static void Plus<T>(this ReadOnlySpan<T?> units, double multiplicator, Span<T?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.PlusCore(multiplicator, len, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Plus<T>(this double multiplicator, ReadOnlySpan<T> units, Span<T> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(multiplicator, destination);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Plus<T>(this double multiplicator, ReadOnlySpan<T?> units, Span<T?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(multiplicator, destination);
|
||||||
|
|
||||||
// === Array ===
|
// === Array ===
|
||||||
public static T[] Plus<T>(this T[] units, double summand)
|
public static T[] Plus<T>(this T[] units, double summand)
|
||||||
@@ -114,20 +140,8 @@ public static partial class CollectionsPlusExtensions
|
|||||||
int len = units.Length;
|
int len = units.Length;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
// Выделяем чистую память (0 аллокаций логики, только сам массив)
|
|
||||||
var result = new T?[len];
|
var result = new T?[len];
|
||||||
|
Plus(units, summand, result);
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
// Читаем из исходного по значению (бесплатно для 8 байт)
|
|
||||||
T? item = units[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
// Пишем напрямую в результат по ref-ссылке (всего 1 запись в память!)
|
|
||||||
ref var dst = ref result[i];
|
|
||||||
dst = (item.Value.ToDouble() + summand).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,16 +173,7 @@ public static partial class CollectionsPlusExtensions
|
|||||||
if (count == 0) return [];
|
if (count == 0) return [];
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
var resultArray = new T?[count];
|
||||||
ReadOnlySpan<T?> srcSpan = CollectionsMarshal.AsSpan(units);
|
Plus(CollectionsMarshal.AsSpan(units), summand, resultArray);
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
T? item = srcSpan[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (item.Value.ToDouble() + summand).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,123 +186,90 @@ public static partial class CollectionsPlusExtensions
|
|||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
// === ICollection<T> ===
|
||||||
public static ICollection<T> Plus<T>(this ICollection<T> units, double summand)
|
public static void Plus<T>(this ICollection<T> units, double summand, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Plus(summand);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Plus(summand);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { array.Plus(summand, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedArray, 0);
|
foreach (var item in units)
|
||||||
Plus(new ReadOnlySpan<T>(sharedArray, 0, count), summand, finalResult.AsSpan());
|
destination[i++] = (item.ToDouble() + summand).ToUnit<T>();
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static ICollection<T?> Plus<T>(this ICollection<T?> units, double summand)
|
public static void Plus<T>(this ICollection<T?> units, double summand, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Plus(summand);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Plus(summand);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
var resultArray = new T?[count];
|
if (units is T?[] array) { array.Plus(summand, destination); return; }
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedNullableArray, 0);
|
foreach (var item in units)
|
||||||
var srcSpan = new ReadOnlySpan<T?>(sharedNullableArray, 0, count);
|
destination[i++] = item.HasValue
|
||||||
srcSpan.Plus(summand, resultArray);
|
? (item.Value.ToDouble() + summand).ToUnit<T>() : null;
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ICollection<T> Plus<T>(this double summand, ICollection<T> units)
|
public static void Plus<T>(this double summand, ICollection<T> units, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ICollection<T?> Plus<T>(this double summand, ICollection<T?> units)
|
public static void Plus<T>(this double summand, ICollection<T?> units, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
public static IReadOnlyCollection<T> Plus<T>(this IReadOnlyCollection<T> units, double summand)
|
public static void Plus<T>(this IReadOnlyCollection<T> units, double summand, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Plus(summand);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Plus(summand);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(count);
|
if (units is T[] array) { array.Plus(summand, destination); return; }
|
||||||
var finalResult = new T[count];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
foreach (var item in units)
|
||||||
foreach (var item in units) sharedArray[index++] = item;
|
destination[i++] = (item.ToDouble() + summand).ToUnit<T>();
|
||||||
Plus(sharedArray, summand, finalResult.AsSpan());
|
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static IReadOnlyCollection<T?> Plus<T>(this IReadOnlyCollection<T?> units, double summand)
|
public static void Plus<T>(this IReadOnlyCollection<T?> units, double summand, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int count = units.Count;
|
int count = units.Count;
|
||||||
if (count == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Plus(summand);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Plus(summand);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(count);
|
if (units is T?[] array) { array.Plus(summand, destination); return; }
|
||||||
var resultArray = new T?[count];
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
int index = 0;
|
foreach (var item in units)
|
||||||
foreach (var item in units) sharedNullableArray[index++] = item;
|
destination[i++] = item.HasValue
|
||||||
for (int i = 0; i < count; i++)
|
? (item.Value.ToDouble() + summand).ToUnit<T>() : null;
|
||||||
{
|
|
||||||
T? item = sharedNullableArray[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = (item.Value.ToDouble() + summand).ToUnit<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static IReadOnlyCollection<T> Plus<T>(this double summand, IReadOnlyCollection<T> units)
|
public static void Plus<T>(this double summand, IReadOnlyCollection<T> units, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static IReadOnlyCollection<T?> Plus<T>(this double summand, IReadOnlyCollection<T?> units)
|
public static void Plus<T>(this double summand, IReadOnlyCollection<T?> units, Span<T?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
|
||||||
|
|
||||||
// === IEnumerable<T> + yeild ===
|
// === IEnumerable<T> + yeild ===
|
||||||
static IEnumerable<T> PlusIterator<T>(IEnumerable<T> units, double summand)
|
static IEnumerable<T> PlusIterator<T>(IEnumerable<T> units, double summand)
|
||||||
@@ -321,8 +293,18 @@ public static partial class CollectionsPlusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Plus(summand);
|
if (units is T[] array) return array.Plus(summand);
|
||||||
if (units is List<T> list) return list.Plus(summand);
|
if (units is List<T> list) return list.Plus(summand);
|
||||||
if (units is ICollection<T> col) return col.Plus(summand);
|
if (units is ICollection<T> col)
|
||||||
if (units is IReadOnlyCollection<T> roc) return roc.Plus(summand);
|
{
|
||||||
|
var arr = new T[col.Count];
|
||||||
|
col.Plus(summand, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = new T[roc.Count];
|
||||||
|
roc.Plus(summand, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return PlusIterator(units, summand);
|
return PlusIterator(units, summand);
|
||||||
}
|
}
|
||||||
public static IEnumerable<T?> Plus<T>(this IEnumerable<T?> units, double summand)
|
public static IEnumerable<T?> Plus<T>(this IEnumerable<T?> units, double summand)
|
||||||
@@ -331,8 +313,18 @@ public static partial class CollectionsPlusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Plus(summand);
|
if (units is T?[] array) return array.Plus(summand);
|
||||||
if (units is List<T?> list) return list.Plus(summand);
|
if (units is List<T?> list) return list.Plus(summand);
|
||||||
if (units is ICollection<T?> col) return col.Plus(summand);
|
if (units is ICollection<T?> col)
|
||||||
if (units is IReadOnlyCollection<T?> roc) return roc.Plus(summand);
|
{
|
||||||
|
var arr = new T?[col.Count];
|
||||||
|
col.Plus(summand, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = new T?[roc.Count];
|
||||||
|
roc.Plus(summand, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
return PlusNullableIterator(units, summand);
|
return PlusNullableIterator(units, summand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Buffers;
|
using System.Runtime.Intrinsics;
|
||||||
using System.Runtime.Intrinsics;
|
|
||||||
using System.Runtime.Intrinsics.X86;
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Extensions;
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
@@ -26,16 +25,11 @@ public static partial class CollectionsPowExtensions
|
|||||||
|
|
||||||
// === ЦЕЛАЯ СТЕПЕНЬ ==========================================
|
// === ЦЕЛАЯ СТЕПЕНЬ ==========================================
|
||||||
|
|
||||||
// === ReadOnlySpan === SIMD
|
// === PowCore === SIMD
|
||||||
internal static void Pow<T, R>(this ReadOnlySpan<T> units, int power, Span<R> destination)
|
internal static void PowCore<T, R>(this ReadOnlySpan<T> units, int power, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
int len = units.Length;
|
|
||||||
if (len == 0) return;
|
|
||||||
if (len > destination.Length)
|
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
|
||||||
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
@@ -111,15 +105,10 @@ public static partial class CollectionsPowExtensions
|
|||||||
Unsafe.Add(ref dstRef, i) = power < 0 ? 1.0 / result : result;
|
Unsafe.Add(ref dstRef, i) = power < 0 ? 1.0 / result : result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal static void Pow<T, R>(this ReadOnlySpan<T?> units, int power, Span<R?> destination)
|
internal static void PowCore<T, R>(this ReadOnlySpan<T?> units, int power, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
int len = units.Length;
|
|
||||||
if (len == 0) return;
|
|
||||||
if (len > destination.Length)
|
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
|
||||||
|
|
||||||
// Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора
|
// Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
@@ -158,6 +147,31 @@ public static partial class CollectionsPowExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// === ReadOnlySpan
|
||||||
|
internal static void Pow<T, R>(this ReadOnlySpan<T> units, int power, Span<R> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
int len = units.Length;
|
||||||
|
if (len == 0) return;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.PowCore(power, len, destination);
|
||||||
|
}
|
||||||
|
internal static void Pow<T, R>(this ReadOnlySpan<T?> units, int power, Span<R?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
int len = units.Length;
|
||||||
|
if (len == 0) return;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.PowCore(power, len, destination);
|
||||||
|
}
|
||||||
|
|
||||||
// === Array ===
|
// === Array ===
|
||||||
internal static R[] Pow<T, R>(this T[] units, int power)
|
internal static R[] Pow<T, R>(this T[] units, int power)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -221,7 +235,7 @@ public static partial class CollectionsPowExtensions
|
|||||||
if (destination.Length < count)
|
if (destination.Length < count)
|
||||||
throw new ArgumentException("Destination too short");
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
if (units is T[] array) { array.AsSpan().Pow(power, destination); return; }
|
if (units is T[] array) { array.Pow(power, destination); return; }
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -238,7 +252,7 @@ public static partial class CollectionsPowExtensions
|
|||||||
if (destination.Length < count)
|
if (destination.Length < count)
|
||||||
throw new ArgumentException("Destination too short");
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
if (units is T?[] array) { array.AsSpan().Pow(power, destination); return; }
|
if (units is T?[] array) { array.Pow(power, destination); return; }
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -258,7 +272,7 @@ public static partial class CollectionsPowExtensions
|
|||||||
if (destination.Length < count)
|
if (destination.Length < count)
|
||||||
throw new ArgumentException("Destination too short");
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
if (units is T[] array) { array.AsSpan().Pow(power, destination); return; }
|
if (units is T[] array) { array.Pow(power, destination); return; }
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -275,7 +289,7 @@ public static partial class CollectionsPowExtensions
|
|||||||
if (destination.Length < count)
|
if (destination.Length < count)
|
||||||
throw new ArgumentException("Destination too short");
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
if (units is T?[] array) { array.AsSpan().Pow(power, destination); return; }
|
if (units is T?[] array) { array.Pow(power, destination); return; }
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -309,8 +323,18 @@ public static partial class CollectionsPowExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Pow<T, R>(power);
|
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 List<T> list) return list.Pow<T, R>(power);
|
||||||
if (units is ICollection<T> col) return col.Pow<T, R>(power);
|
if (units is ICollection<T> col)
|
||||||
if (units is IReadOnlyCollection<T> roc) return roc.Pow<T, R>(power);
|
{
|
||||||
|
var arr = new R[col.Count];
|
||||||
|
col.Pow(power, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = new R[roc.Count];
|
||||||
|
roc.Pow(power, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
else return PowIterator<T, R>(units, power);
|
else return PowIterator<T, R>(units, power);
|
||||||
}
|
}
|
||||||
internal static IEnumerable<R?> Pow<T, R>(this IEnumerable<T?> units, int power)
|
internal static IEnumerable<R?> Pow<T, R>(this IEnumerable<T?> units, int power)
|
||||||
@@ -320,24 +344,29 @@ public static partial class CollectionsPowExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Pow<T, R>(power);
|
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 List<T?> list) return list.Pow<T, R>(power);
|
||||||
if (units is ICollection<T?> col) return col.Pow<T, R>(power);
|
if (units is ICollection<T?> col)
|
||||||
if (units is IReadOnlyCollection<T?> roc) return roc.Pow<T, R>(power);
|
{
|
||||||
|
var arr = new R?[col.Count];
|
||||||
|
col.Pow(power, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = new R?[roc.Count];
|
||||||
|
roc.Pow(power, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
else return PowNullableIterator<T, R>(units, power);
|
else return PowNullableIterator<T, R>(units, power);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// === ДРОБНАЯ СТЕПЕНЬ ==========================================
|
// === ДРОБНАЯ СТЕПЕНЬ ==========================================
|
||||||
|
|
||||||
// === ReadOnlySpan ===
|
// === PowCore === SIMD
|
||||||
internal static void Pow<T, R>(this ReadOnlySpan<T> units, double power, Span<R> destination)
|
internal static void PowCore<T, R>(this ReadOnlySpan<T> units, double power, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
int len = units.Length;
|
|
||||||
if (len == 0) return;
|
|
||||||
if (len > destination.Length)
|
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
|
||||||
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
@@ -413,15 +442,10 @@ public static partial class CollectionsPowExtensions
|
|||||||
Unsafe.Add(ref dstRef, i) = Math.Pow(Unsafe.Add(ref srcRef, i), power);
|
Unsafe.Add(ref dstRef, i) = Math.Pow(Unsafe.Add(ref srcRef, i), power);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal static void Pow<T, R>(this ReadOnlySpan<T?> units, double power, Span<R?> destination)
|
internal static void PowCore<T, R>(this ReadOnlySpan<T?> units, double power, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
int len = units.Length;
|
|
||||||
if (len == 0) return;
|
|
||||||
if (len > destination.Length)
|
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
|
||||||
|
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
T? item = units[i];
|
T? item = units[i];
|
||||||
@@ -434,6 +458,32 @@ public static partial class CollectionsPowExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// === ReadOnlySpan ===
|
||||||
|
internal static void Pow<T, R>(this ReadOnlySpan<T> units, double power, Span<R> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
int len = units.Length;
|
||||||
|
if (len == 0) return;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.PowCore(power, len, destination);
|
||||||
|
}
|
||||||
|
internal static void Pow<T, R>(this ReadOnlySpan<T?> units, double power, Span<R?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
int len = units.Length;
|
||||||
|
if (len == 0) return;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.PowCore(power, len, destination);
|
||||||
|
}
|
||||||
|
|
||||||
// === Array ===
|
// === Array ===
|
||||||
internal static R[] Pow<T, R>(this T[] units, double power)
|
internal static R[] Pow<T, R>(this T[] units, double power)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -443,35 +493,20 @@ public static partial class CollectionsPowExtensions
|
|||||||
int len = units.Length;
|
int len = units.Length;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
var finalResult = new R[len];
|
var result = new R[len];
|
||||||
if (power != 0.5)
|
units.Pow(power, result);
|
||||||
{
|
return result;
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
ref var dst = ref finalResult[i];
|
|
||||||
dst = Math.Pow(units[i].ToDouble(), power).ToUnit<R>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else MemoryMarshal.Cast<T, R>(units).Sqrt(finalResult);
|
|
||||||
return finalResult;
|
|
||||||
}
|
}
|
||||||
internal static R?[] Pow<T, R>(this T?[] units, double power)
|
internal static R?[] Pow<T, R>(this T?[] units, double power)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units.Length == 0) return [];
|
int len = units.Length;
|
||||||
|
if (len == 0) return [];
|
||||||
|
|
||||||
var result = (R?[])units.Clone();
|
var result = new R?[len];
|
||||||
int len = result.Length;
|
units.Pow(power, result);
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
ref var item = ref result[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
item = Math.Pow(item.Value.ToDouble(), power).ToUnit<R>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,23 +519,9 @@ public static partial class CollectionsPowExtensions
|
|||||||
int len = units.Count;
|
int len = units.Count;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
var resultArray = new R[len];
|
var result = new R[len];
|
||||||
var srcSpan = CollectionsMarshal.AsSpan(units);
|
CollectionsMarshal.AsSpan(units).Pow(power, result);
|
||||||
if (power == 0.5)
|
return result.WrapAsList();
|
||||||
{
|
|
||||||
ReadOnlySpan<R> srcAsR = MemoryMarshal.Cast<T, R>(srcSpan);
|
|
||||||
srcAsR.Sqrt(resultArray);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Span<R> dstSpan = resultArray.AsSpan();
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
ref var dst = ref dstSpan[i];
|
|
||||||
dst = Math.Pow(srcSpan[i].ToDouble(), power).ToUnit<R>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray.WrapAsList();
|
|
||||||
}
|
}
|
||||||
internal static List<R?> Pow<T, R>(this List<T?> units, double power)
|
internal static List<R?> Pow<T, R>(this List<T?> units, double power)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -510,155 +531,83 @@ public static partial class CollectionsPowExtensions
|
|||||||
int len = units.Count;
|
int len = units.Count;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
var resultArray = new R?[len];
|
var result = new R?[len];
|
||||||
var srcSpan = CollectionsMarshal.AsSpan(units);
|
CollectionsMarshal.AsSpan(units).Pow(power, result);
|
||||||
for (int i = 0; i < len; i++)
|
return result.WrapAsList();
|
||||||
{
|
|
||||||
T? item = srcSpan[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = Math.Pow(item.Value.ToDouble(), power).ToUnit<R>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray.WrapAsList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<Length> ===
|
// === ICollection<Length> ===
|
||||||
internal static ICollection<R> Pow<T, R>(this ICollection<T> units, double power)
|
internal static void Pow<T, R>(this ICollection<T> units, double power, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int len = units.Count;
|
int count = units.Count;
|
||||||
if (len == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Pow<T, R>(power);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Pow<T, R>(power);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(len);
|
if (units is T[] array) { array.Pow(power, destination); return; }
|
||||||
var finalResult = new R[len];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedArray, 0);
|
foreach (T item in units)
|
||||||
if (power == 0.5)
|
destination[i++] = Math.Pow(item.ToDouble(), power).ToUnit<R>();
|
||||||
{
|
|
||||||
MemoryMarshal.Cast<T, R>(sharedArray).Sqrt(finalResult);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
finalResult[i] = Math.Pow(sharedArray[i].ToDouble(), power).ToUnit<R>();
|
|
||||||
}
|
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
internal static ICollection<R?> Pow<T, R>(this ICollection<T?> units, double power)
|
internal static void Pow<T, R>(this ICollection<T?> units, double power, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int len = units.Count;
|
int count = units.Count;
|
||||||
if (len == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Pow<T, R>(power);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Pow<T, R>(power);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(len);
|
if (units is T?[] array) { array.Pow(power, destination); return; }
|
||||||
var finalResult = new R?[len];
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedNullableArray, 0);
|
foreach (T? item in units)
|
||||||
for (int i = 0; i < len; i++)
|
destination[i++] = item.HasValue
|
||||||
{
|
? Math.Pow(item.Value.ToDouble(), power).ToUnit<R>() : null;
|
||||||
T? item = sharedNullableArray[i];
|
|
||||||
finalResult[i] = item.HasValue ? Math.Pow(item.Value.ToDouble(), power).ToUnit<R>() : default;
|
|
||||||
}
|
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IReadOnlyCollection<Length> ===
|
// === IReadOnlyCollection<Length> ===
|
||||||
internal static IReadOnlyCollection<R> Pow<T, R>(this IReadOnlyCollection<T> units, double power)
|
internal static void Pow<T, R>(this IReadOnlyCollection<T> units, double power, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int len = units.Count;
|
int count = units.Count;
|
||||||
if (len == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Pow<T, R>(power);
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Pow<T, R>(power);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
var finalResult = new R[len];
|
if (units is T[] array) { array.Pow(power, destination); return; }
|
||||||
var sharedArray = ArrayPool<T>.Shared.Rent(len);
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||||
try
|
|
||||||
{
|
|
||||||
if (units is ICollection<T> collection)
|
|
||||||
{
|
|
||||||
collection.CopyTo(sharedArray, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int idx = 0;
|
|
||||||
foreach (var item in units) sharedArray[idx++] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (power != 0.5)
|
int i = 0;
|
||||||
{
|
foreach (T item in units)
|
||||||
for (int i = 0; i < len; i++)
|
destination[i++] = Math.Pow(item.ToDouble(), power).ToUnit<R>();
|
||||||
finalResult[i] = Math.Pow(sharedArray[i].ToDouble(), power).ToUnit<R>();
|
|
||||||
}
|
|
||||||
else MemoryMarshal.Cast<T, R>(sharedArray).Sqrt(finalResult);
|
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
internal static IReadOnlyCollection<R?> Pow<T, R>(this IReadOnlyCollection<T?> units, double power)
|
internal static void Pow<T, R>(this IReadOnlyCollection<T?> units, double power, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int len = units.Count;
|
int count = units.Count;
|
||||||
if (len == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Pow<T, R>(power);
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Pow<T, R>(power);
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
var finalResult = new R?[len];
|
if (units is T?[] array) { array.Pow(power, destination); return; }
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(len);
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
||||||
|
|
||||||
try
|
int i = 0;
|
||||||
{
|
foreach (T? item in units)
|
||||||
if (units is ICollection<T?> collection)
|
destination[i++] = item.HasValue
|
||||||
{
|
? Math.Pow(item.Value.ToDouble(), power).ToUnit<R>() : null;
|
||||||
collection.CopyTo(sharedNullableArray, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int idx = 0;
|
|
||||||
foreach (T? item in units) sharedNullableArray[idx++] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
T? item = sharedNullableArray[i];
|
|
||||||
finalResult[i] = item.HasValue ? Math.Pow(item.Value.ToDouble(), power).ToUnit<R>() : default;
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IEnumerable<Length> + yield ===
|
// === IEnumerable<Length> + yield ===
|
||||||
@@ -686,8 +635,18 @@ public static partial class CollectionsPowExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Pow<T, R>(power);
|
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 List<T> list) return list.Pow<T, R>(power);
|
||||||
if (units is ICollection<T> col) return col.Pow<T, R>(power);
|
if (units is ICollection<T> col)
|
||||||
if (units is IReadOnlyCollection<T> roc) return roc.Pow<T, R>(power);
|
{
|
||||||
|
var arr = new R[col.Count];
|
||||||
|
col.Pow(power, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = new R[roc.Count];
|
||||||
|
roc.Pow(power, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
else return PowIterator<T, R>(units, power);
|
else return PowIterator<T, R>(units, power);
|
||||||
}
|
}
|
||||||
internal static IEnumerable<R?> Pow<T, R>(this IEnumerable<T?> units, double power)
|
internal static IEnumerable<R?> Pow<T, R>(this IEnumerable<T?> units, double power)
|
||||||
@@ -697,8 +656,18 @@ public static partial class CollectionsPowExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Pow<T, R>(power);
|
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 List<T?> list) return list.Pow<T, R>(power);
|
||||||
if (units is ICollection<T?> col) return col.Pow<T, R>(power);
|
if (units is ICollection<T?> col)
|
||||||
if (units is IReadOnlyCollection<T?> roc) return roc.Pow<T, R>(power);
|
{
|
||||||
|
var arr = new R?[col.Count];
|
||||||
|
col.Pow(power, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = new R?[roc.Count];
|
||||||
|
roc.Pow(power, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
else return PowNullableIterator<T, R>(units, power);
|
else return PowNullableIterator<T, R>(units, power);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,14 @@
|
|||||||
using System.Buffers;
|
using System.Runtime.Intrinsics.X86;
|
||||||
using System.Runtime.Intrinsics;
|
|
||||||
using System.Runtime.Intrinsics.X86;
|
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Extensions;
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
|
|
||||||
public static partial class CollectionsSqrtExtensions
|
public static partial class CollectionsSqrtExtensions
|
||||||
{
|
{
|
||||||
// === ReadOnlySpan === SIMD
|
// === SqrtCore === SIMD
|
||||||
internal static void Sqrt<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
|
internal static unsafe void SqrtCore<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units.IsEmpty) return;
|
|
||||||
int len = units.Length;
|
|
||||||
if (len > destination.Length)
|
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
|
||||||
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
@@ -27,21 +20,21 @@ public static partial class CollectionsSqrtExtensions
|
|||||||
// 1. ПУТЬ AVX (x64 Процессоры Intel/AMD) — обрабатываем по 4 элемента double
|
// 1. ПУТЬ AVX (x64 Процессоры Intel/AMD) — обрабатываем по 4 элемента double
|
||||||
if (Avx.IsSupported && len >= 4)
|
if (Avx.IsSupported && len >= 4)
|
||||||
{
|
{
|
||||||
int simdEnd = len & ~3; // Вычисляем границу по маске (быстрее, чем len - len % 4)
|
int simdEnd = len & ~3;
|
||||||
|
|
||||||
for (; i < simdEnd; i += 4)
|
for (; i < simdEnd; i += 4)
|
||||||
{
|
{
|
||||||
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
|
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
|
||||||
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
|
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
|
||||||
|
|
||||||
// Загружаем 4 элемента double в AVX регистр за 1 такт
|
// Получаем указатели через Unsafe.AsPointer
|
||||||
var v = Unsafe.As<double, Vector256<double>>(ref currentSrc);
|
double* pSrc = (double*)Unsafe.AsPointer(ref currentSrc);
|
||||||
|
double* pDst = (double*)Unsafe.AsPointer(ref currentDst);
|
||||||
|
|
||||||
// Аппаратный корень на уровне CPU
|
// Выровненная загрузка (требует, чтобы pSrc был кратен 32)
|
||||||
|
var v = Avx.LoadVector256(pSrc);
|
||||||
var sqrtV = Avx.Sqrt(v);
|
var sqrtV = Avx.Sqrt(v);
|
||||||
|
// Выровненное сохранение
|
||||||
// Выгружаем результат обратно в память назначения за 1 такт
|
Avx.Store(pDst, sqrtV);
|
||||||
Unsafe.As<double, Vector256<double>>(ref currentDst) = sqrtV;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2. ПУТЬ VECTOR (ARM64 / Apple Silicon / Старые CPU без AVX)
|
// 2. ПУТЬ VECTOR (ARM64 / Apple Silicon / Старые CPU без AVX)
|
||||||
@@ -69,15 +62,10 @@ public static partial class CollectionsSqrtExtensions
|
|||||||
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
|
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Sqrt<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
|
public static void SqrtCore<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units.IsEmpty) return;
|
|
||||||
int len = units.Length;
|
|
||||||
if (len > destination.Length)
|
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
|
||||||
|
|
||||||
// Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора
|
// Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
@@ -115,6 +103,33 @@ public static partial class CollectionsSqrtExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// === ReadOnlySpan ===
|
||||||
|
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>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.SqrtCore(len, destination);
|
||||||
|
}
|
||||||
|
public static void Sqrt<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.SqrtCore(len, destination);
|
||||||
|
}
|
||||||
|
|
||||||
// === Array ===
|
// === Array ===
|
||||||
public static R[] Sqrt<T, R>(this T[] units)
|
public static R[] Sqrt<T, R>(this T[] units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -161,69 +176,82 @@ public static partial class CollectionsSqrtExtensions
|
|||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
var resultArray = new R?[len];
|
var resultArray = new R?[len];
|
||||||
var srcSpan = CollectionsMarshal.AsSpan(units);
|
Sqrt(CollectionsMarshal.AsSpan(units), resultArray);
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
T? item = srcSpan[i];
|
|
||||||
if (item.HasValue)
|
|
||||||
{
|
|
||||||
ref var dst = ref resultArray[i];
|
|
||||||
dst = Math.Sqrt(item.Value.ToDouble()).ToUnit<R>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<Length> ===
|
// === ICollection<Length> ===
|
||||||
public static ICollection<R> Sqrt<T, R>(this ICollection<T> units)
|
public static void Sqrt<T, R>(this ICollection<T> units, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int len = units.Count;
|
int count = units.Count;
|
||||||
if (len == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T[] array) return array.Sqrt<T, R>();
|
if (destination.Length < count)
|
||||||
if (units is List<T> list) return list.Sqrt<T, R>();
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(len);
|
if (units is T[] array) { array.Sqrt(destination); return; }
|
||||||
var finalResult = new R[len];
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedArray, 0);
|
foreach (T item in units)
|
||||||
MemoryMarshal.Cast<T, R>(sharedArray).Sqrt(finalResult);
|
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||||
return finalResult;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static ICollection<R?> Sqrt<T, R>(this ICollection<T?> units)
|
public static void Sqrt<T, R>(this ICollection<T?> units, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return;
|
||||||
int len = units.Count;
|
int count = units.Count;
|
||||||
if (len == 0) return [];
|
if (count == 0) return;
|
||||||
if (units is T?[] array) return array.Sqrt<T, R>();
|
if (destination.Length < count)
|
||||||
if (units is List<T?> list) return list.Sqrt<T, R>();
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
T?[] sharedNullableArray = ArrayPool<T?>.Shared.Rent(len);
|
if (units is T?[] array) { array.Sqrt(destination); return; }
|
||||||
var finalResult = new R?[len];
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
||||||
try
|
|
||||||
{
|
int i = 0;
|
||||||
units.CopyTo(sharedNullableArray, 0);
|
foreach (T? item in units)
|
||||||
for (int i = 0; i < len; i++)
|
destination[i++] = item.HasValue
|
||||||
{
|
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
T? item = sharedNullableArray[i];
|
}
|
||||||
finalResult[i] = item.HasValue ? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : default;
|
|
||||||
}
|
// === IReadOnlyCollection<Length> ===
|
||||||
return finalResult;
|
public static void Sqrt<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
||||||
}
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
finally
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
ArrayPool<T?>.Shared.Return(sharedNullableArray);
|
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>();
|
||||||
|
}
|
||||||
|
public static void Sqrt<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.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IEnumerable<Length> + yield ===
|
// === IEnumerable<Length> + yield ===
|
||||||
@@ -244,26 +272,46 @@ public static partial class CollectionsSqrtExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// === IEnumerable<Length> ===
|
// === IEnumerable<Length> ===
|
||||||
internal static IEnumerable<R> Sqrt<T, R>(this IEnumerable<T> units, double Sqrter)
|
internal static IEnumerable<R> Sqrt<T, R>(this IEnumerable<T> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Sqrt<T, R>(Sqrter);
|
if (units is T[] array) return array.Sqrt<T, R>();
|
||||||
if (units is List<T> list) return list.Sqrt<T, R>(Sqrter);
|
if (units is List<T> list) return list.Sqrt<T, R>();
|
||||||
if (units is ICollection<T> col) return col.Sqrt<T, R>(Sqrter);
|
if (units is ICollection<T> col)
|
||||||
if (units is IReadOnlyCollection<T> roc) return roc.Sqrt<T, R>(Sqrter);
|
{
|
||||||
|
var arr = new R[col.Count];
|
||||||
|
col.Sqrt(arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = new R[roc.Count];
|
||||||
|
roc.Sqrt(arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
else return SqrtIterator<T, R>(units);
|
else return SqrtIterator<T, R>(units);
|
||||||
}
|
}
|
||||||
internal static IEnumerable<R?> Sqrt<T, R>(this IEnumerable<T?> units, double Sqrter)
|
internal static IEnumerable<R?> Sqrt<T, R>(this IEnumerable<T?> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Sqrt<T, R>(Sqrter);
|
if (units is T?[] array) return array.Sqrt<T, R>();
|
||||||
if (units is List<T?> list) return list.Sqrt<T, R>(Sqrter);
|
if (units is List<T?> list) return list.Sqrt<T, R>();
|
||||||
if (units is ICollection<T?> col) return col.Sqrt<T, R>(Sqrter);
|
if (units is ICollection<T?> col)
|
||||||
if (units is IReadOnlyCollection<T?> roc) return roc.Sqrt<T, R>(Sqrter);
|
{
|
||||||
|
var arr = new R?[col.Count];
|
||||||
|
col.Sqrt(arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = new R?[roc.Count];
|
||||||
|
roc.Sqrt(arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
else return SqrtNullableIterator<T, R>(units);
|
else return SqrtNullableIterator<T, R>(units);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System.Globalization;
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Extensions;
|
|
||||||
|
|
||||||
internal static partial class ToDoubleExtensions
|
internal static partial class ToDoubleExtensions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,231 +1,231 @@
|
|||||||
namespace QWERTYkez.Mensura.Units;
|
//namespace QWERTYkez.Mensura.Units;
|
||||||
|
|
||||||
internal static class OperationsExtension
|
//internal static class OperationsExtension
|
||||||
{
|
|
||||||
internal static TResult MultiplyProtected<T1, T2, TResult>(this T1 t1, T2 t2)
|
|
||||||
where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
|
||||||
where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
|
||||||
where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
|
||||||
=> new() { Value = t1.Value * t2.Value };
|
|
||||||
|
|
||||||
internal static TResult MultiplyProtected<T1, T2, TResult>(this T1 t1, T2 t2, double multiplicator)
|
|
||||||
where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
|
||||||
where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
|
||||||
where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
|
||||||
=> new() { Value = t1.Value * t2.Value * multiplicator };
|
|
||||||
|
|
||||||
internal static TResult DivideProtected<T1, T2, TResult>(this T1 t1, T2 t2)
|
|
||||||
where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
|
||||||
where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
|
||||||
where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
|
||||||
=> new() { Value = t1.Value / t2.Value };
|
|
||||||
|
|
||||||
internal static TResult DivideProtected<T1, T2, TResult>(this T1 t1, T2 t2, double multiplicator)
|
|
||||||
where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
|
||||||
where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
|
||||||
where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
|
||||||
=> new() { Value = t1.Value * multiplicator / t2.Value };
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class Coefficients
|
|
||||||
{
|
|
||||||
internal static double MultiplyCoefficient<T1, T2, TResult>(T1 a, T2 b, TResult r)
|
|
||||||
where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
|
||||||
where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
|
||||||
where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
|
||||||
=> r.Value / (a.Value * b.Value);
|
|
||||||
|
|
||||||
internal static double DivideCoefficient<T1, T2, TResult>(T1 a, T2 b, TResult r)
|
|
||||||
where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
|
||||||
where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
|
||||||
where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
|
||||||
=> r.Value * b.Value / a.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Length
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Area operator *(Length left, Length right)
|
|
||||||
=> left.MultiplyProtected<Length, Length, Area>(right, Coeff1);
|
|
||||||
|
|
||||||
static readonly double Coeff1 = Coefficients.MultiplyCoefficient(MilliMeter, MilliMeter, Area.MilliMeterSquared);
|
|
||||||
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Volume operator *(Area left, Length right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Volume operator *(Length left, Area right)
|
|
||||||
=> left.MultiplyProtected<Length, Area, Volume>(right, Coeff2);
|
|
||||||
|
|
||||||
static readonly double Coeff2 = Coefficients.MultiplyCoefficient(MilliMeter, Area.MilliMeterSquared, Volume.MilliMeterCubic);
|
|
||||||
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Pressure operator *(Length left, UdelForce right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Pressure operator *(UdelForce left, Length right) => left.MultiplyProtected<UdelForce, Length, Pressure>(right, Coeff3);
|
|
||||||
static readonly double Coeff3 = Coefficients.MultiplyCoefficient(a => a.PerMeterCubic.Newtons = 1, Length.Meter, Pressure.NewtonPerMeterSquared);
|
|
||||||
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Force operator *(PogonForce left, Length right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Force operator *(Length left, PogonForce right) => left.MultiplyProtected<Length, PogonForce, Force>(right, Coeff4);
|
|
||||||
static readonly double Coeff4 = Coefficients.MultiplyCoefficient(Length.Meter, b => b.PerMeter.Newtons = 1, Force.Newton);
|
|
||||||
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Torque operator *(Force left, Length right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Torque operator *(Length left, Force right) => left.MultiplyProtected<Length, Force, Torque>(right, Coeff6);
|
|
||||||
static readonly double Coeff6 = Coefficients.MultiplyCoefficient(Length.Meter, Force.Newton, Torque.Newton_Meter);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Mass // Grams
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Pressure // Pascals
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Length operator /(Pressure left, UdelForce right) => left.DivideProtected<Pressure, UdelForce, Length>(right, Coeff1);
|
|
||||||
static readonly double Coeff1 = Coefficients.DivideCoefficient(Pressure.Pascal, b => b.PerMeterCubic.Newtons = 1, Length.Meter);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Force operator *(Pressure left, Area right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Force operator *(Area left, Pressure right) => left.MultiplyProtected<Area, Pressure, Force>(right, Coeff2);
|
|
||||||
static readonly double Coeff2 = Coefficients.MultiplyCoefficient(Area.MeterSquared, Pressure.Pascal, Force.Newton);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Length operator /(PogonForce left, Pressure right) => left.DivideProtected<PogonForce, Pressure, Length>(right, Coeff3);
|
|
||||||
static readonly double Coeff3 = Coefficients.DivideCoefficient(a => a._PerMilliMeter.Newtons = 1, Pressure.NewtonPerMilliMeterSquared, Length.MilliMeter);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static PogonForce operator *(Pressure left, Length right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static PogonForce operator *(Length left, Pressure right) => left.MultiplyProtected<Length, Pressure, PogonForce>(right, Coeff4);
|
|
||||||
static readonly double Coeff4 = Coefficients.MultiplyCoefficient(Length.MilliMeter, Pressure.NewtonPerMilliMeterSquared, r => r._PerMilliMeter.Newtons = 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Area // MilliMetersSquared
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Torque operator *(PogonForce left, Area right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Torque operator *(Area left, PogonForce right) => left.MultiplyProtected<Area, PogonForce, Torque>(right, Coeff1);
|
|
||||||
static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Area.MeterSquared, b => b.PerMeter.Newtons = 1, Torque.Newton_Meter);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Length operator /(Area left, Length right) => left.DivideProtected<Area, Length, Length>(right, Coeff2);
|
|
||||||
static readonly double Coeff2 = Coefficients.DivideCoefficient(Area.MilliMeterSquared, Length.MilliMeter, Length.MilliMeter);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Volume // MillimetersCubic
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Mass operator *(Density left, Volume right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Mass operator *(Volume left, Density right) => left.MultiplyProtected<Volume, Density, Mass>(right, Coeff1);
|
|
||||||
static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Volume.MilliMeterCubic, b => b.PerMilliMeterCubic.Grams = 1, Time.Gram);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Torque operator *(Pressure left, Volume right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Torque operator *(Volume left, Pressure right) => left.MultiplyProtected<Volume, Pressure, Torque>(right, Coeff2);
|
|
||||||
static readonly double Coeff2 = Coefficients.MultiplyCoefficient(Volume.MeterCubic, Pressure.Pascal, Torque.Newton_Meter);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Area operator /(Volume left, Length right) => left.DivideProtected<Volume, Length, Area>(right);
|
|
||||||
[CollectionsOperatorsGenerator] public static Length operator /(Volume left, Area right) => left.DivideProtected<Volume, Area, Length>(right, Coeff3);
|
|
||||||
static readonly double Coeff3 = Coefficients.DivideCoefficient(Volume.MilliMeterCubic, Length.MilliMeter, Area.MilliMeterSquared);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Force // Newtons
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Area operator /(Force left, Pressure right) => left.DivideProtected<Force, Pressure, Area>(right, Coeff1);
|
|
||||||
static readonly double Coeff1 = Coefficients.DivideCoefficient(Force.Newton, Pressure.Pascal, Area.MeterSquared);
|
|
||||||
[CollectionsOperatorsGenerator] public static Pressure operator /(Force left, Area right) => left.DivideProtected<Force, Area, Pressure>(right, Coeff2);
|
|
||||||
static readonly double Coeff2 = Coefficients.DivideCoefficient(Force.Newton, Area.MeterSquared, Pressure.Pascal);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Torque // NewtonMeters
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Length operator /(Torque left, Force right) => left.DivideProtected<Torque, Force, Length>(right, Coeff1);
|
|
||||||
static readonly double Coeff1 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Force.Newton, Length.Meter);
|
|
||||||
[CollectionsOperatorsGenerator] public static Force operator /(Torque left, Length right) => left.DivideProtected<Torque, Length, Force>(right, Coeff2);
|
|
||||||
static readonly double Coeff2 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Length.Meter, Force.Newton);
|
|
||||||
[CollectionsOperatorsGenerator] public static PogonForce operator /(Torque left, Area right) => left.DivideProtected<Torque, Area, PogonForce>(right, Coeff3);
|
|
||||||
static readonly double Coeff3 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Area.MilliMeterSquared, r => r.PerMilliMeter.KiloNewtons = 1);
|
|
||||||
[CollectionsOperatorsGenerator] public static Pressure operator /(Torque left, Volume right) => left.DivideProtected<Torque, Volume, Pressure>(right, Coeff4);
|
|
||||||
static readonly double Coeff4 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Volume.MeterCubic, Pressure.Pascal);
|
|
||||||
[CollectionsOperatorsGenerator] public static Volume operator /(Torque left, Pressure right) => left.DivideProtected<Torque, Pressure, Volume>(right, Coeff5);
|
|
||||||
static readonly double Coeff5 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Pressure.Pascal, Volume.MeterCubic);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Frequency // Hertz
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Time
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Speed operator *(Boost left, Time right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Speed operator *(Time left, Boost right) => left.MultiplyProtected<Time, Boost, Speed>(right, Coeff1);
|
|
||||||
static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Time.Second, Boost.MeterPerSecondSquared, Speed.MeterPerSecond);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Speed operator /(Length left, Time right) => left.DivideProtected<Length, Time, Speed>(right, Coeff2);
|
|
||||||
static readonly double Coeff2 = Coefficients.DivideCoefficient(Length.Meter, Time.Second, Speed.MeterPerSecond);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Speed
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Length operator *(Speed left, Time right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Length operator *(Time left, Speed right) => left.MultiplyProtected<Time, Speed, Length>(right, Coeff1);
|
|
||||||
static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Time.Second, Speed.MeterPerSecond, Length.Meter);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Boost operator /(Speed left, Time right) => left.DivideProtected<Speed, Time, Boost>(right, Coeff2);
|
|
||||||
static readonly double Coeff2 = Coefficients.DivideCoefficient(Speed.MeterPerSecond, Time.Second, Boost.MeterPerSecondSquared);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct Boost
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Force operator *(Mass left, Boost right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Force operator *(Boost left, Mass right) => left.MultiplyProtected<Boost, Mass, Force>(right, Coeff1);
|
|
||||||
static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Boost.MeterPerSecondSquared, Time.KiloGram, Force.Newton);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static PogonForce operator *(PogonMass left, Boost right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static PogonForce operator *(Boost left, PogonMass right) => left.MultiplyProtected<Boost, PogonMass, PogonForce>(right, Coeff2);
|
|
||||||
static readonly double Coeff2 = Coefficients.MultiplyCoefficient(Boost.MeterPerSecondSquared, b => b.PerMilliMeter.KiloGrams = 1, r => r.PerMilliMeter.Newtons = 1);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static UdelForce operator *(Density left, Boost right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static UdelForce operator *(Boost left, Density right) => left.MultiplyProtected<Boost, Density, UdelForce>(right, Coeff3);
|
|
||||||
static readonly double Coeff3 = Coefficients.MultiplyCoefficient(Boost.MeterPerSecondSquared, b => b.PerMilliMeterCubic.KiloGrams = 1, r => r.PerMilliMeterCubic.Newtons = 1);
|
|
||||||
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static PogonMass operator /(PogonForce left, Boost right) => left.DivideProtected<PogonForce, Boost, PogonMass>(right, Coeff4);
|
|
||||||
static readonly double Coeff4 = Coefficients.DivideCoefficient(a => a.PerMilliMeter.Newtons = 1, Boost.MeterPerSecondSquared, r => r.PerMilliMeter.KiloGrams = 1);
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static Density operator /(UdelForce left, Boost right) => left.DivideProtected<UdelForce, Boost, Density>(right, Coeff5);
|
|
||||||
static readonly double Coeff5 = Coefficients.DivideCoefficient(a => a.PerMilliMeterCubic.Newtons = 1, Boost.MeterPerSecondSquared, r => r.PerMilliMeterCubic.KiloGrams = 1);
|
|
||||||
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static MassPerSquare operator /(Pressure left, Boost right) => left.DivideProtected<Pressure, Boost, MassPerSquare>(right, Coeff6);
|
|
||||||
static readonly double Coeff6 = Coefficients.DivideCoefficient(Pressure.Pascal, Boost.MeterPerSecondSquared, MassPerSquare.KiloGramPerMeterSquared);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public readonly partial record struct MassPerSquare
|
|
||||||
{
|
|
||||||
[CollectionsOperatorsGenerator] public static Pressure operator *(Boost left, MassPerSquare right) => right * left;
|
|
||||||
[CollectionsOperatorsGenerator] public static Pressure operator *(MassPerSquare left, Boost right) => left.MultiplyProtected<MassPerSquare, Boost, Pressure>(right, Coeff1);
|
|
||||||
static readonly double Coeff1 = Coefficients.MultiplyCoefficient(MassPerSquare.KiloGramPerMeterSquared, Boost.MeterPerSecondSquared, Pressure.Pascal);
|
|
||||||
}
|
|
||||||
|
|
||||||
//[CollectionsOperatorsGenerator] public readonly partial record struct PogonForce : Pogon<PogonForce, Force>
|
|
||||||
//{
|
//{
|
||||||
|
// internal static TResult MultiplyProtected<T1, T2, TResult>(this T1 t1, T2 t2)
|
||||||
|
// where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
||||||
|
// where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
||||||
|
// where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
||||||
|
// => new() { Value = t1.Value * t2.Value };
|
||||||
|
|
||||||
|
// internal static TResult MultiplyProtected<T1, T2, TResult>(this T1 t1, T2 t2, double multiplicator)
|
||||||
|
// where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
||||||
|
// where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
||||||
|
// where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
||||||
|
// => new() { Value = t1.Value * t2.Value * multiplicator };
|
||||||
|
|
||||||
|
// internal static TResult DivideProtected<T1, T2, TResult>(this T1 t1, T2 t2)
|
||||||
|
// where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
||||||
|
// where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
||||||
|
// where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
||||||
|
// => new() { Value = t1.Value / t2.Value };
|
||||||
|
|
||||||
|
// internal static TResult DivideProtected<T1, T2, TResult>(this T1 t1, T2 t2, double multiplicator)
|
||||||
|
// where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
||||||
|
// where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
||||||
|
// where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
||||||
|
// => new() { Value = t1.Value * multiplicator / t2.Value };
|
||||||
|
//}
|
||||||
|
|
||||||
|
//internal static class Coefficients
|
||||||
|
//{
|
||||||
|
// internal static double MultiplyCoefficient<T1, T2, TResult>(T1 a, T2 b, TResult r)
|
||||||
|
// where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
||||||
|
// where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
||||||
|
// where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
||||||
|
// => r.Value / (a.Value * b.Value);
|
||||||
|
|
||||||
|
// internal static double DivideCoefficient<T1, T2, TResult>(T1 a, T2 b, TResult r)
|
||||||
|
// where T1 : struct, IMensuraUnit<T1>, IEquatable<T1>, IMensuraUnit
|
||||||
|
// where T2 : struct, IMensuraUnit<T2>, IEquatable<T2>, IMensuraUnit
|
||||||
|
// where TResult : struct, IMensuraUnit<TResult>, IEquatable<TResult>, IMensuraUnit
|
||||||
|
// => r.Value * b.Value / a.Value;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Length
|
||||||
|
//{
|
||||||
|
// [CollectionsOperatorsGenerator] public static Area operator *(Length left, Length right)
|
||||||
|
// => left.MultiplyProtected<Length, Length, Area>(right, Coeff1);
|
||||||
|
|
||||||
|
// static readonly double Coeff1 = Coefficients.MultiplyCoefficient(MilliMeter, MilliMeter, Area.MilliMeterSquared);
|
||||||
|
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Volume operator *(Area left, Length right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Volume operator *(Length left, Area right)
|
||||||
|
// => left.MultiplyProtected<Length, Area, Volume>(right, Coeff2);
|
||||||
|
|
||||||
|
// static readonly double Coeff2 = Coefficients.MultiplyCoefficient(MilliMeter, Area.MilliMeterSquared, Volume.MilliMeterCubic);
|
||||||
|
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Pressure operator *(Length left, UdelForce right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Pressure operator *(UdelForce left, Length right) => left.MultiplyProtected<UdelForce, Length, Pressure>(right, Coeff3);
|
||||||
|
// static readonly double Coeff3 = Coefficients.MultiplyCoefficient(a => a.PerMeterCubic.Newtons = 1, Length.Meter, Pressure.NewtonPerMeterSquared);
|
||||||
|
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Force operator *(PogonForce left, Length right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Force operator *(Length left, PogonForce right) => left.MultiplyProtected<Length, PogonForce, Force>(right, Coeff4);
|
||||||
|
// static readonly double Coeff4 = Coefficients.MultiplyCoefficient(Length.Meter, b => b.PerMeter.Newtons = 1, Force.Newton);
|
||||||
|
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Torque operator *(Force left, Length right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Torque operator *(Length left, Force right) => left.MultiplyProtected<Length, Force, Torque>(right, Coeff6);
|
||||||
|
// static readonly double Coeff6 = Coefficients.MultiplyCoefficient(Length.Meter, Force.Newton, Torque.Newton_Meter);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Mass // Grams
|
||||||
|
//{
|
||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//[CollectionsOperatorsGenerator] public readonly partial record struct PogonMass : Pogon<PogonMass, Mass>
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Pressure // Pascals
|
||||||
//{
|
//{
|
||||||
// [CollectionsOperatorsGenerator] public static Boost operator /(PogonForce left, PogonMass right) => left.DivideProtected<PogonForce, PogonMass, Boost>(right, Coeff1);
|
// [CollectionsOperatorsGenerator] public static Length operator /(Pressure left, UdelForce right) => left.DivideProtected<Pressure, UdelForce, Length>(right, Coeff1);
|
||||||
|
// static readonly double Coeff1 = Coefficients.DivideCoefficient(Pressure.Pascal, b => b.PerMeterCubic.Newtons = 1, Length.Meter);
|
||||||
|
|
||||||
// static readonly double Coeff1 = Coefficients.DivideCoefficient(a => a.PerMilliMeter.Newtons = 1, b => b.PerMilliMeter.KiloGrams = 1, Boost.MeterPerSecondSquared);
|
// [CollectionsOperatorsGenerator] public static Force operator *(Pressure left, Area right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Force operator *(Area left, Pressure right) => left.MultiplyProtected<Area, Pressure, Force>(right, Coeff2);
|
||||||
|
// static readonly double Coeff2 = Coefficients.MultiplyCoefficient(Area.MeterSquared, Pressure.Pascal, Force.Newton);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Length operator /(PogonForce left, Pressure right) => left.DivideProtected<PogonForce, Pressure, Length>(right, Coeff3);
|
||||||
|
// static readonly double Coeff3 = Coefficients.DivideCoefficient(a => a._PerMilliMeter.Newtons = 1, Pressure.NewtonPerMilliMeterSquared, Length.MilliMeter);
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static PogonForce operator *(Pressure left, Length right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static PogonForce operator *(Length left, Pressure right) => left.MultiplyProtected<Length, Pressure, PogonForce>(right, Coeff4);
|
||||||
|
// static readonly double Coeff4 = Coefficients.MultiplyCoefficient(Length.MilliMeter, Pressure.NewtonPerMilliMeterSquared, r => r._PerMilliMeter.Newtons = 1);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//[CollectionsOperatorsGenerator] public readonly partial record struct UdelForce : Udel<UdelForce, Force>
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Area // MilliMetersSquared
|
||||||
//{
|
//{
|
||||||
|
// [CollectionsOperatorsGenerator] public static Torque operator *(PogonForce left, Area right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Torque operator *(Area left, PogonForce right) => left.MultiplyProtected<Area, PogonForce, Torque>(right, Coeff1);
|
||||||
|
// static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Area.MeterSquared, b => b.PerMeter.Newtons = 1, Torque.Newton_Meter);
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Length operator /(Area left, Length right) => left.DivideProtected<Area, Length, Length>(right, Coeff2);
|
||||||
|
// static readonly double Coeff2 = Coefficients.DivideCoefficient(Area.MilliMeterSquared, Length.MilliMeter, Length.MilliMeter);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Volume // MillimetersCubic
|
||||||
|
//{
|
||||||
|
// [CollectionsOperatorsGenerator] public static Mass operator *(Density left, Volume right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Mass operator *(Volume left, Density right) => left.MultiplyProtected<Volume, Density, Mass>(right, Coeff1);
|
||||||
|
// static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Volume.MilliMeterCubic, b => b.PerMilliMeterCubic.Grams = 1, Time.Gram);
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Torque operator *(Pressure left, Volume right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Torque operator *(Volume left, Pressure right) => left.MultiplyProtected<Volume, Pressure, Torque>(right, Coeff2);
|
||||||
|
// static readonly double Coeff2 = Coefficients.MultiplyCoefficient(Volume.MeterCubic, Pressure.Pascal, Torque.Newton_Meter);
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Area operator /(Volume left, Length right) => left.DivideProtected<Volume, Length, Area>(right);
|
||||||
|
// [CollectionsOperatorsGenerator] public static Length operator /(Volume left, Area right) => left.DivideProtected<Volume, Area, Length>(right, Coeff3);
|
||||||
|
// static readonly double Coeff3 = Coefficients.DivideCoefficient(Volume.MilliMeterCubic, Length.MilliMeter, Area.MilliMeterSquared);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Force // Newtons
|
||||||
|
//{
|
||||||
|
// [CollectionsOperatorsGenerator] public static Area operator /(Force left, Pressure right) => left.DivideProtected<Force, Pressure, Area>(right, Coeff1);
|
||||||
|
// static readonly double Coeff1 = Coefficients.DivideCoefficient(Force.Newton, Pressure.Pascal, Area.MeterSquared);
|
||||||
|
// [CollectionsOperatorsGenerator] public static Pressure operator /(Force left, Area right) => left.DivideProtected<Force, Area, Pressure>(right, Coeff2);
|
||||||
|
// static readonly double Coeff2 = Coefficients.DivideCoefficient(Force.Newton, Area.MeterSquared, Pressure.Pascal);
|
||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//[CollectionsOperatorsGenerator] public readonly partial record struct Density : Udel<Density, Mass>
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Torque // NewtonMeters
|
||||||
|
//{
|
||||||
|
// [CollectionsOperatorsGenerator] public static Length operator /(Torque left, Force right) => left.DivideProtected<Torque, Force, Length>(right, Coeff1);
|
||||||
|
// static readonly double Coeff1 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Force.Newton, Length.Meter);
|
||||||
|
// [CollectionsOperatorsGenerator] public static Force operator /(Torque left, Length right) => left.DivideProtected<Torque, Length, Force>(right, Coeff2);
|
||||||
|
// static readonly double Coeff2 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Length.Meter, Force.Newton);
|
||||||
|
// [CollectionsOperatorsGenerator] public static PogonForce operator /(Torque left, Area right) => left.DivideProtected<Torque, Area, PogonForce>(right, Coeff3);
|
||||||
|
// static readonly double Coeff3 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Area.MilliMeterSquared, r => r.PerMilliMeter.KiloNewtons = 1);
|
||||||
|
// [CollectionsOperatorsGenerator] public static Pressure operator /(Torque left, Volume right) => left.DivideProtected<Torque, Volume, Pressure>(right, Coeff4);
|
||||||
|
// static readonly double Coeff4 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Volume.MeterCubic, Pressure.Pascal);
|
||||||
|
// [CollectionsOperatorsGenerator] public static Volume operator /(Torque left, Pressure right) => left.DivideProtected<Torque, Pressure, Volume>(right, Coeff5);
|
||||||
|
// static readonly double Coeff5 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Pressure.Pascal, Volume.MeterCubic);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Frequency // Hertz
|
||||||
//{
|
//{
|
||||||
|
|
||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Time
|
||||||
|
//{
|
||||||
|
// [CollectionsOperatorsGenerator] public static Speed operator *(Boost left, Time right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Speed operator *(Time left, Boost right) => left.MultiplyProtected<Time, Boost, Speed>(right, Coeff1);
|
||||||
|
// static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Time.Second, Boost.MeterPerSecondSquared, Speed.MeterPerSecond);
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Speed operator /(Length left, Time right) => left.DivideProtected<Length, Time, Speed>(right, Coeff2);
|
||||||
|
// static readonly double Coeff2 = Coefficients.DivideCoefficient(Length.Meter, Time.Second, Speed.MeterPerSecond);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Speed
|
||||||
|
//{
|
||||||
|
// [CollectionsOperatorsGenerator] public static Length operator *(Speed left, Time right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Length operator *(Time left, Speed right) => left.MultiplyProtected<Time, Speed, Length>(right, Coeff1);
|
||||||
|
// static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Time.Second, Speed.MeterPerSecond, Length.Meter);
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Boost operator /(Speed left, Time right) => left.DivideProtected<Speed, Time, Boost>(right, Coeff2);
|
||||||
|
// static readonly double Coeff2 = Coefficients.DivideCoefficient(Speed.MeterPerSecond, Time.Second, Boost.MeterPerSecondSquared);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[CollectionsOperatorsGenerator] public readonly partial record struct Boost
|
||||||
|
//{
|
||||||
|
// [CollectionsOperatorsGenerator] public static Force operator *(Mass left, Boost right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Force operator *(Boost left, Mass right) => left.MultiplyProtected<Boost, Mass, Force>(right, Coeff1);
|
||||||
|
// static readonly double Coeff1 = Coefficients.MultiplyCoefficient(Boost.MeterPerSecondSquared, Time.KiloGram, Force.Newton);
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static PogonForce operator *(PogonMass left, Boost right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static PogonForce operator *(Boost left, PogonMass right) => left.MultiplyProtected<Boost, PogonMass, PogonForce>(right, Coeff2);
|
||||||
|
// static readonly double Coeff2 = Coefficients.MultiplyCoefficient(Boost.MeterPerSecondSquared, b => b.PerMilliMeter.KiloGrams = 1, r => r.PerMilliMeter.Newtons = 1);
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static UdelForce operator *(Density left, Boost right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static UdelForce operator *(Boost left, Density right) => left.MultiplyProtected<Boost, Density, UdelForce>(right, Coeff3);
|
||||||
|
// static readonly double Coeff3 = Coefficients.MultiplyCoefficient(Boost.MeterPerSecondSquared, b => b.PerMilliMeterCubic.KiloGrams = 1, r => r.PerMilliMeterCubic.Newtons = 1);
|
||||||
|
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static PogonMass operator /(PogonForce left, Boost right) => left.DivideProtected<PogonForce, Boost, PogonMass>(right, Coeff4);
|
||||||
|
// static readonly double Coeff4 = Coefficients.DivideCoefficient(a => a.PerMilliMeter.Newtons = 1, Boost.MeterPerSecondSquared, r => r.PerMilliMeter.KiloGrams = 1);
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static Density operator /(UdelForce left, Boost right) => left.DivideProtected<UdelForce, Boost, Density>(right, Coeff5);
|
||||||
|
// static readonly double Coeff5 = Coefficients.DivideCoefficient(a => a.PerMilliMeterCubic.Newtons = 1, Boost.MeterPerSecondSquared, r => r.PerMilliMeterCubic.KiloGrams = 1);
|
||||||
|
|
||||||
|
|
||||||
|
// [CollectionsOperatorsGenerator] public static MassPerSquare operator /(Pressure left, Boost right) => left.DivideProtected<Pressure, Boost, MassPerSquare>(right, Coeff6);
|
||||||
|
// static readonly double Coeff6 = Coefficients.DivideCoefficient(Pressure.Pascal, Boost.MeterPerSecondSquared, MassPerSquare.KiloGramPerMeterSquared);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[CollectionsOperatorsGenerator] public readonly partial record struct MassPerSquare
|
||||||
|
//{
|
||||||
|
// [CollectionsOperatorsGenerator] public static Pressure operator *(Boost left, MassPerSquare right) => right * left;
|
||||||
|
// [CollectionsOperatorsGenerator] public static Pressure operator *(MassPerSquare left, Boost right) => left.MultiplyProtected<MassPerSquare, Boost, Pressure>(right, Coeff1);
|
||||||
|
// static readonly double Coeff1 = Coefficients.MultiplyCoefficient(MassPerSquare.KiloGramPerMeterSquared, Boost.MeterPerSecondSquared, Pressure.Pascal);
|
||||||
|
//}
|
||||||
|
|
||||||
|
////[CollectionsOperatorsGenerator] public readonly partial record struct PogonForce : Pogon<PogonForce, Force>
|
||||||
|
////{
|
||||||
|
|
||||||
|
|
||||||
|
////}
|
||||||
|
|
||||||
|
////[CollectionsOperatorsGenerator] public readonly partial record struct PogonMass : Pogon<PogonMass, Mass>
|
||||||
|
////{
|
||||||
|
//// [CollectionsOperatorsGenerator] public static Boost operator /(PogonForce left, PogonMass right) => left.DivideProtected<PogonForce, PogonMass, Boost>(right, Coeff1);
|
||||||
|
|
||||||
|
//// static readonly double Coeff1 = Coefficients.DivideCoefficient(a => a.PerMilliMeter.Newtons = 1, b => b.PerMilliMeter.KiloGrams = 1, Boost.MeterPerSecondSquared);
|
||||||
|
////}
|
||||||
|
|
||||||
|
////[CollectionsOperatorsGenerator] public readonly partial record struct UdelForce : Udel<UdelForce, Force>
|
||||||
|
////{
|
||||||
|
|
||||||
|
|
||||||
|
////}
|
||||||
|
|
||||||
|
////[CollectionsOperatorsGenerator] public readonly partial record struct Density : Udel<Density, Mass>
|
||||||
|
////{
|
||||||
|
|
||||||
|
|
||||||
|
////}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
namespace MetricSystem;
|
//namespace MetricSystem;
|
||||||
|
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// Base value is PerMilliMeter
|
///// Base value is PerMilliMeter
|
||||||
/// </summary>
|
///// </summary>
|
||||||
public abstract class Pogon<T>
|
//public abstract class Pogon<T>
|
||||||
{
|
//{
|
||||||
|
|
||||||
|
|
||||||
internal T PerValue { get; init; }
|
// internal T PerValue { get; init; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -15,135 +15,135 @@ public abstract class Pogon<T>
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[NotMapped, JsonIgnore] internal T PerValue
|
// [NotMapped, JsonIgnore] internal T PerValue
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value
|
// SilentValueSetter = Value
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value;
|
// Value = value.Value;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T _PerMilliMeter
|
// [NotMapped, JsonIgnore] public T _PerMilliMeter
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value
|
// SilentValueSetter = Value
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value;
|
// Value = value.Value;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
[NotMapped, JsonIgnore] public T PerMilliMeter
|
// [NotMapped, JsonIgnore] public T PerMilliMeter
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value
|
// SilentValueSetter = Value
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value;
|
// Value = value.Value;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T PerCentiMeter
|
// [NotMapped, JsonIgnore] public T PerCentiMeter
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value * LengthConv.CentiMeters.Multiplicator,
|
// SilentValueSetter = Value * LengthConv.CentiMeters.Multiplicator,
|
||||||
BaseContainerMultiplicator = LengthConv.CentiMeters.Multiplicator,
|
// BaseContainerMultiplicator = LengthConv.CentiMeters.Multiplicator,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value / LengthConv.CentiMeters.Multiplicator;
|
// Value = value.Value / LengthConv.CentiMeters.Multiplicator;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T PerDeciMeter
|
// [NotMapped, JsonIgnore] public T PerDeciMeter
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value * LengthConv.DeciMeters.Multiplicator,
|
// SilentValueSetter = Value * LengthConv.DeciMeters.Multiplicator,
|
||||||
BaseContainerMultiplicator = LengthConv.DeciMeters.Multiplicator,
|
// BaseContainerMultiplicator = LengthConv.DeciMeters.Multiplicator,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value / LengthConv.DeciMeters.Multiplicator;
|
// Value = value.Value / LengthConv.DeciMeters.Multiplicator;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T PerMeter
|
// [NotMapped, JsonIgnore] public T PerMeter
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value * LengthConv.Meters.Multiplicator,
|
// SilentValueSetter = Value * LengthConv.Meters.Multiplicator,
|
||||||
BaseContainerMultiplicator = LengthConv.Meters.Multiplicator,
|
// BaseContainerMultiplicator = LengthConv.Meters.Multiplicator,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value / LengthConv.Meters.Multiplicator;
|
// Value = value.Value / LengthConv.Meters.Multiplicator;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T PerKiloMeter
|
// [NotMapped, JsonIgnore] public T PerKiloMeter
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value * LengthConv.KiloMeters.Multiplicator,
|
// SilentValueSetter = Value * LengthConv.KiloMeters.Multiplicator,
|
||||||
BaseContainerMultiplicator = LengthConv.KiloMeters.Multiplicator,
|
// BaseContainerMultiplicator = LengthConv.KiloMeters.Multiplicator,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value / LengthConv.KiloMeters.Multiplicator;
|
// Value = value.Value / LengthConv.KiloMeters.Multiplicator;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
public static T operator *(Pogon<U, T> left, Length right) => ((U)left).Protect()._PerMilliMeter * right.Protect()._MilliMeters;
|
// public static T operator *(Pogon<U, T> left, Length right) => ((U)left).Protect()._PerMilliMeter * right.Protect()._MilliMeters;
|
||||||
public static MetricCollection<T> operator *(Pogon<U, T> left, MetricCollection<Length> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
// public static MetricCollection<T> operator *(Pogon<U, T> left, MetricCollection<Length> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
||||||
public static MetricArray<T> operator *(Pogon<U, T> left, MetricArray<Length> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
// public static MetricArray<T> operator *(Pogon<U, T> left, MetricArray<Length> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
||||||
public static MetricList<T> operator *(Pogon<U, T> left, MetricList<Length> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
// public static MetricList<T> operator *(Pogon<U, T> left, MetricList<Length> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
||||||
public static MetricObservableCollection<T> operator *(Pogon<U, T> left, MetricObservableCollection<Length> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
// public static MetricObservableCollection<T> operator *(Pogon<U, T> left, MetricObservableCollection<Length> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
||||||
|
|
||||||
|
|
||||||
public static T operator *(Length left, Pogon<U, T> right) => ((U)right).Protect()._PerMilliMeter * left.Protect()._MilliMeters;
|
// public static T operator *(Length left, Pogon<U, T> right) => ((U)right).Protect()._PerMilliMeter * left.Protect()._MilliMeters;
|
||||||
public static MetricCollection<T> operator *(MetricCollection<Length> left, Pogon<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
// public static MetricCollection<T> operator *(MetricCollection<Length> left, Pogon<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
||||||
public static MetricArray<T> operator *(MetricArray<Length> left, Pogon<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
// public static MetricArray<T> operator *(MetricArray<Length> left, Pogon<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
||||||
public static MetricList<T> operator *(MetricList<Length> left, Pogon<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
// public static MetricList<T> operator *(MetricList<Length> left, Pogon<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
||||||
public static MetricObservableCollection<T> operator *(MetricObservableCollection<Length> left, Pogon<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
// public static MetricObservableCollection<T> operator *(MetricObservableCollection<Length> left, Pogon<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
||||||
|
|
||||||
|
|
||||||
public static Length operator /(T left, Pogon<U, T> right) => new() { _MilliMeters = left.Protect() / ((U)right).Protect()._PerMilliMeter };
|
// public static Length operator /(T left, Pogon<U, T> right) => new() { _MilliMeters = left.Protect() / ((U)right).Protect()._PerMilliMeter };
|
||||||
public static MetricCollection<Length> operator *(MetricCollection<T> left, Pogon<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
// public static MetricCollection<Length> operator *(MetricCollection<T> left, Pogon<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
||||||
public static MetricArray<Length> operator *(MetricArray<T> left, Pogon<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
// public static MetricArray<Length> operator *(MetricArray<T> left, Pogon<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
||||||
public static MetricList<Length> operator *(MetricList<T> left, Pogon<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
// public static MetricList<Length> operator *(MetricList<T> left, Pogon<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
||||||
public static MetricObservableCollection<Length> operator *(MetricObservableCollection<T> left, Pogon<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
// public static MetricObservableCollection<Length> operator *(MetricObservableCollection<T> left, Pogon<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
||||||
}
|
//}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
namespace MetricSystem;
|
//namespace MetricSystem;
|
||||||
|
|
||||||
[DebuggerDisplay("N/m = {PerMeter._Newtons.ToString(\"0.###\")}, kgf/m = {PerMeter.KiloGramXXXXXXXXs.ToString(\"0.###\")}")]
|
//[DebuggerDisplay("N/m = {PerMeter._Newtons.ToString(\"0.###\")}, kgf/m = {PerMeter.KiloGramXXXXXXXXs.ToString(\"0.###\")}")]
|
||||||
public readonly partial record struct PogonXXXXXXXX
|
//public readonly partial record struct PogonXXXXXXXX
|
||||||
{
|
//{
|
||||||
|
|
||||||
|
|
||||||
}
|
//}
|
||||||
|
|
||||||
public partial class Length : Metric<Length, Length>
|
//public partial class Length : Metric<Length, Length>
|
||||||
{
|
//{
|
||||||
[CollectionsOperatorsGenerator] public static PogonXXXXXXXX operator /(XXXXXXXX left, Length right) => left.DivideProtected<XXXXXXXX, Length, PogonXXXXXXXX>(right, PogonXXXXXXXXCoeff);
|
// [CollectionsOperatorsGenerator] public static PogonXXXXXXXX operator /(XXXXXXXX left, Length right) => left.DivideProtected<XXXXXXXX, Length, PogonXXXXXXXX>(right, PogonXXXXXXXXCoeff);
|
||||||
static readonly double PogonXXXXXXXXCoeff = Coefficients.DivideCoefficient<XXXXXXXX, Length, PogonXXXXXXXX>(a => a.Value = 1, b => b._MilliMeters = 1, r => r._PerMilliMeter.Value = 1);
|
// static readonly double PogonXXXXXXXXCoeff = Coefficients.DivideCoefficient<XXXXXXXX, Length, PogonXXXXXXXX>(a => a.Value = 1, b => b._MilliMeters = 1, r => r._PerMilliMeter.Value = 1);
|
||||||
}
|
//}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
namespace MetricSystem;
|
//namespace MetricSystem;
|
||||||
|
|
||||||
[Owned, JsonConverter(typeof(MetricFormatter<PogonMass>)), DebuggerDisplay("gr/m = {PerMeter._Grams.ToString(\"0.###\")}, kg/m = {PerMeter.KiloGrams.ToString(\"0.###\")}")]
|
//[Owned, JsonConverter(typeof(MetricFormatter<PogonMass>)), DebuggerDisplay("gr/m = {PerMeter._Grams.ToString(\"0.###\")}, kg/m = {PerMeter.KiloGrams.ToString(\"0.###\")}")]
|
||||||
public partial class PogonMass : Pogon<PogonMass, Mass>
|
//public partial class PogonMass : Pogon<PogonMass, Mass>
|
||||||
{
|
//{
|
||||||
[CollectionsOperatorsGenerator] public static Density operator /(PogonMass left, Area right) => left.DivideProtected<PogonMass, Area, Density>(right, UdelMassCoeff);
|
// [CollectionsOperatorsGenerator] public static Density operator /(PogonMass left, Area right) => left.DivideProtected<PogonMass, Area, Density>(right, UdelMassCoeff);
|
||||||
static readonly double UdelMassCoeff = Coefficients.DivideCoefficient<PogonMass, Area, Density>(a => a._PerMilliMeter.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeterCubic.Value = 1);
|
// static readonly double UdelMassCoeff = Coefficients.DivideCoefficient<PogonMass, Area, Density>(a => a._PerMilliMeter.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeterCubic.Value = 1);
|
||||||
}
|
//}
|
||||||
|
|
||||||
public partial class Length : Metric<Length, Length>
|
//public partial class Length : Metric<Length, Length>
|
||||||
{
|
//{
|
||||||
[CollectionsOperatorsGenerator] public static PogonMass operator /(Mass left, Length right) => left.DivideProtected<Mass, Length, PogonMass>(right, PogonMassCoeff);
|
// [CollectionsOperatorsGenerator] public static PogonMass operator /(Mass left, Length right) => left.DivideProtected<Mass, Length, PogonMass>(right, PogonMassCoeff);
|
||||||
static readonly double PogonMassCoeff = Coefficients.DivideCoefficient<Mass, Length, PogonMass>(a => a.Value = 1, b => b._MilliMeters = 1, r => r._PerMilliMeter.Value = 1);
|
// static readonly double PogonMassCoeff = Coefficients.DivideCoefficient<Mass, Length, PogonMass>(a => a.Value = 1, b => b._MilliMeters = 1, r => r._PerMilliMeter.Value = 1);
|
||||||
}
|
//}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
global using PogonMass = QWERTYkez.Mensura.Units.Pogon.PogonMass;
|
|
||||||
global using PogonMassExtensions = QWERTYkez.Mensura.Units.Pogon.PogonMassExtensions;
|
global using PogonMassExtensions = QWERTYkez.Mensura.Units.Pogon.PogonMassExtensions;
|
||||||
global using PogonMassConverter = QWERTYkez.Mensura.Units.Pogon.PogonMassConverter;
|
global using PogonMassConverter = QWERTYkez.Mensura.Units.Pogon.PogonMassConverter;
|
||||||
|
global using PogonMass = QWERTYkez.Mensura.Units.Pogon.PogonMass;
|
||||||
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
@@ -10,6 +10,146 @@ namespace QWERTYkez.Mensura.Units
|
|||||||
{
|
{
|
||||||
public readonly partial record struct Length
|
public readonly partial record struct Length
|
||||||
{
|
{
|
||||||
|
// === Array ===
|
||||||
|
public static Mass[] operator *(PogonMass[] units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len == 0) return [];
|
||||||
|
|
||||||
|
var result = new Mass[len];
|
||||||
|
units.MultiplyCore(multiplicator._Value, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public static Mass?[] operator *(PogonMass?[] units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len == 0) return [];
|
||||||
|
|
||||||
|
var result = new Mass?[len];
|
||||||
|
units.MultiplyCore(multiplicator._Value, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Mass[] operator *(Length multiplicator, PogonMass[] units) => units * multiplicator;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Mass?[] operator *(Length multiplicator, PogonMass?[] units) => units * multiplicator;
|
||||||
|
|
||||||
|
// === List<T> ===
|
||||||
|
public static List<Mass> operator *(List<PogonMass> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int len = units.Count;
|
||||||
|
if (len == 0) return [];
|
||||||
|
|
||||||
|
var resultArray = new Mass[len];
|
||||||
|
Multiply(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
|
||||||
|
return resultArray.WrapAsList();
|
||||||
|
}
|
||||||
|
public static List<Mass?> operator *(List<PogonMass?> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int count = units.Count;
|
||||||
|
if (count == 0) return [];
|
||||||
|
|
||||||
|
var resultArray = new Mass?[count];
|
||||||
|
Multiply(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
|
||||||
|
return resultArray.WrapAsList();
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Mass> operator *(
|
||||||
|
Length multiplicator, List<PogonMass> units) => units * multiplicator;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Mass?> operator *(
|
||||||
|
Length multiplicator, List<PogonMass?> units) => units * multiplicator;
|
||||||
|
|
||||||
|
// === IEnumerable<T> ===
|
||||||
|
public static IEnumerable<Mass> Multiply(IEnumerable<PogonMass> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
if (units is PogonMass[] array) return array.Multiply(multiplicator);
|
||||||
|
if (units is List<PogonMass> list) return list.Multiply(multiplicator);
|
||||||
|
if (units is ICollection<PogonMass> col)
|
||||||
|
{
|
||||||
|
var arr = new Mass[col.Count];
|
||||||
|
col.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<PogonMass> roc)
|
||||||
|
{
|
||||||
|
var arr = new Mass[roc.Count];
|
||||||
|
roc.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
return MultiplyIterator(units, multiplicator);
|
||||||
|
}
|
||||||
|
public static IEnumerable<Mass?> Multiply(IEnumerable<PogonMass?> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
if (units is PogonMass?[] array) return array.Multiply(multiplicator);
|
||||||
|
if (units is List<PogonMass?> list) return list.Multiply(multiplicator);
|
||||||
|
if (units is ICollection<PogonMass?> col)
|
||||||
|
{
|
||||||
|
var arr = new Mass?[col.Count];
|
||||||
|
col.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<PogonMass?> roc)
|
||||||
|
{
|
||||||
|
var arr = new Mass?[roc.Count];
|
||||||
|
roc.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
return MultiplyNullableIterator(units, multiplicator);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Mass> Multiply(
|
||||||
|
Length multiplicator, IEnumerable<PogonMass> units) => Multiply(units, multiplicator);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Mass?> Multiply(
|
||||||
|
Length multiplicator, IEnumerable<PogonMass?> units) => Multiply(units, multiplicator);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// === MULTIPLY ===
|
// === MULTIPLY ===
|
||||||
// ==========================================
|
// ==========================================
|
||||||
@@ -83,7 +223,7 @@ namespace QWERTYkez.Mensura.Units
|
|||||||
result[i] = val * right[i];
|
result[i] = val * right[i];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static Span<Mass> operator *(this ReadOnlySpan<PogonMass> left, Length right)
|
public static Span<Mass> operator *(ReadOnlySpan<PogonMass> left, Length right)
|
||||||
{
|
{
|
||||||
int len = left.Length;
|
int len = left.Length;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
@@ -93,7 +233,7 @@ namespace QWERTYkez.Mensura.Units
|
|||||||
result[i] = right * left[i];
|
result[i] = right * left[i];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static Span<Mass> operator *(this ReadOnlySpan<PogonMass> left, Length? right)
|
public static Span<Mass> operator *(ReadOnlySpan<PogonMass> left, Length? right)
|
||||||
{
|
{
|
||||||
int len = left.Length;
|
int len = left.Length;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
@@ -277,7 +417,7 @@ namespace QWERTYkez.Mensura.Units.Pogon
|
|||||||
result[i] = val * right[i];
|
result[i] = val * right[i];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static Span<Mass> operator *(this ReadOnlySpan<Length> left, PogonMass right)
|
public static Span<Mass> operator *(ReadOnlySpan<Length> left, PogonMass right)
|
||||||
{
|
{
|
||||||
int len = left.Length;
|
int len = left.Length;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
@@ -287,7 +427,7 @@ namespace QWERTYkez.Mensura.Units.Pogon
|
|||||||
result[i] = right * left[i];
|
result[i] = right * left[i];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static Span<Mass> operator *(this ReadOnlySpan<Length> left, PogonMass? right)
|
public static Span<Mass> operator *(ReadOnlySpan<Length> left, PogonMass? right)
|
||||||
{
|
{
|
||||||
int len = left.Length;
|
int len = left.Length;
|
||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
@@ -364,70 +504,261 @@ namespace QWERTYkez.Mensura.Units.Pogon
|
|||||||
public static PogonMass MetricAverage(this IEnumerable<PogonMass?> units) => new(units?.Average(m => m.ToDouble()) ?? double.NaN);
|
public static PogonMass MetricAverage(this IEnumerable<PogonMass?> units) => new(units?.Average(m => m.ToDouble()) ?? double.NaN);
|
||||||
public static PogonMass MetricMax(this IEnumerable<PogonMass?> units) => new(units?.Max(m => m.ToDouble()) ?? double.MinValue);
|
public static PogonMass MetricMax(this IEnumerable<PogonMass?> units) => new(units?.Max(m => m.ToDouble()) ?? double.MinValue);
|
||||||
public static PogonMass MetricMin(this IEnumerable<PogonMass?> units) => new(units?.Min(m => m.ToDouble()) ?? double.MaxValue);
|
public static PogonMass MetricMin(this IEnumerable<PogonMass?> units) => new(units?.Min(m => m.ToDouble()) ?? double.MaxValue);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// === ReadOnlySpan
|
||||||
|
public static void Multiply(this ReadOnlySpan<PogonMass> units, Length multiplicator, Span<Mass> destination)
|
||||||
|
=> units.MultiplyCore(multiplicator._Value, destination);
|
||||||
|
public static void Multiply(this ReadOnlySpan<PogonMass?> units, Length multiplicator, Span<Mass?> destination)
|
||||||
|
=> units.MultiplyCore(multiplicator._Value, destination);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Multiply(this Length multiplicator,
|
||||||
|
ReadOnlySpan<PogonMass> units, Span<Mass> destination) => units.MultiplyCore(multiplicator._Value, destination);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Multiply(this Length multiplicator,
|
||||||
|
ReadOnlySpan<PogonMass?> units, Span<Mass?> destination) => units.MultiplyCore(multiplicator._Value, destination);
|
||||||
|
|
||||||
|
// === Array ===
|
||||||
|
public static Mass[] Multiply(this PogonMass[] units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len == 0) return [];
|
||||||
|
|
||||||
|
var result = new Mass[len];
|
||||||
|
Multiply(units, multiplicator, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public static Mass?[] Multiply(this PogonMass?[] units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len == 0) return [];
|
||||||
|
|
||||||
|
var result = new Mass?[len];
|
||||||
|
Multiply(units, multiplicator, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Mass[] Multiply(
|
||||||
|
this Length multiplicator, PogonMass[] units) => units.Multiply(multiplicator);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Mass?[] Multiply(
|
||||||
|
this Length multiplicator, PogonMass?[] units) => units.Multiply(multiplicator);
|
||||||
|
|
||||||
|
// === List<T> ===
|
||||||
|
public static List<Mass> Multiply(this List<PogonMass> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int len = units.Count;
|
||||||
|
if (len == 0) return [];
|
||||||
|
|
||||||
|
var resultArray = new Mass[len];
|
||||||
|
Multiply(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
|
||||||
|
return resultArray.WrapAsList();
|
||||||
|
}
|
||||||
|
public static List<Mass?> Multiply(this List<PogonMass?> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int count = units.Count;
|
||||||
|
if (count == 0) return [];
|
||||||
|
|
||||||
|
var resultArray = new Mass?[count];
|
||||||
|
Multiply(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
|
||||||
|
return resultArray.WrapAsList();
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static List<Mass> Multiply(
|
||||||
|
this Length multiplicator, List<PogonMass> units) => units.Multiply(multiplicator);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static List<Mass?> Multiply(
|
||||||
|
this Length multiplicator, List<PogonMass?> units) => units.Multiply(multiplicator);
|
||||||
|
|
||||||
|
// === ICollection<T> ===
|
||||||
|
public static void Multiply(this ICollection<PogonMass> units, Length multiplicator, Span<Mass> destination)
|
||||||
|
{
|
||||||
|
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 PogonMass[] array) { array.Multiply(multiplicator, destination); return; }
|
||||||
|
if (units is List<PogonMass> list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; }
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (var item in units)
|
||||||
|
destination[i++] = (item.ToDouble() * multiplicator._Value).ToUnit<Mass>();
|
||||||
|
}
|
||||||
|
public static void Multiply(this ICollection<PogonMass?> units, Length multiplicator, Span<Mass?> destination)
|
||||||
|
{
|
||||||
|
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 PogonMass?[] array) { array.Multiply(multiplicator, destination); return; }
|
||||||
|
if (units is List<PogonMass?> list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; }
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (var item in units)
|
||||||
|
destination[i++] = item.HasValue
|
||||||
|
? (item.Value.ToDouble() * multiplicator._Value).ToUnit<Mass>() : null;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Multiply(this Length multiplicator,
|
||||||
|
ICollection<PogonMass> units, Span<Mass> destination) => units.Multiply(multiplicator, destination);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Multiply(this Length multiplicator,
|
||||||
|
ICollection<PogonMass?> units, Span<Mass?> destination) => units.Multiply(multiplicator, destination);
|
||||||
|
|
||||||
|
// === IReadOnlyCollection<T> ===
|
||||||
|
public static void Multiply(this IReadOnlyCollection<PogonMass> units, Length multiplicator, Span<Mass> destination)
|
||||||
|
{
|
||||||
|
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 PogonMass[] array) { array.Multiply(multiplicator, destination); return; }
|
||||||
|
if (units is List<PogonMass> list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; }
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (var item in units)
|
||||||
|
destination[i++] = (item.ToDouble() * multiplicator._Value).ToUnit<Mass>();
|
||||||
|
}
|
||||||
|
public static void Multiply(this IReadOnlyCollection<PogonMass?> units, Length multiplicator, Span<Mass?> destination)
|
||||||
|
{
|
||||||
|
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 PogonMass?[] array) { array.Multiply(multiplicator, destination); return; }
|
||||||
|
if (units is List<PogonMass?> list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; }
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (var item in units)
|
||||||
|
destination[i++] = item.HasValue
|
||||||
|
? (item.Value.ToDouble() * multiplicator._Value).ToUnit<Mass>() : null;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Multiply(this Length multiplicator,
|
||||||
|
IReadOnlyCollection<PogonMass> units, Span<Mass> destination) => units.Multiply(multiplicator, destination);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Multiply(this Length multiplicator,
|
||||||
|
IReadOnlyCollection<PogonMass?> units, Span<Mass?> destination) => units.Multiply(multiplicator, destination);
|
||||||
|
|
||||||
|
// === IEnumerable<T> + yeild ===
|
||||||
|
static IEnumerable<Mass> MultiplyIterator(IEnumerable<PogonMass> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
foreach (var item in units)
|
||||||
|
yield return (item.ToDouble() * multiplicator._Value).ToUnit<Mass>();
|
||||||
|
}
|
||||||
|
static IEnumerable<Mass?> MultiplyNullableIterator(IEnumerable<PogonMass?> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
foreach (PogonMass? item in units)
|
||||||
|
yield return item.HasValue
|
||||||
|
? (item.Value.ToDouble() * multiplicator._Value).ToUnit<Mass>() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === IEnumerable<T> ===
|
||||||
|
public static IEnumerable<Mass> Multiply(this IEnumerable<PogonMass> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
if (units is PogonMass[] array) return array.Multiply(multiplicator);
|
||||||
|
if (units is List<PogonMass> list) return list.Multiply(multiplicator);
|
||||||
|
if (units is ICollection<PogonMass> col)
|
||||||
|
{
|
||||||
|
var arr = new Mass[col.Count];
|
||||||
|
col.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<PogonMass> roc)
|
||||||
|
{
|
||||||
|
var arr = new Mass[roc.Count];
|
||||||
|
roc.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
return MultiplyIterator(units, multiplicator);
|
||||||
|
}
|
||||||
|
public static IEnumerable<Mass?> Multiply(this IEnumerable<PogonMass?> units, Length multiplicator)
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
if (units is PogonMass?[] array) return array.Multiply(multiplicator);
|
||||||
|
if (units is List<PogonMass?> list) return list.Multiply(multiplicator);
|
||||||
|
if (units is ICollection<PogonMass?> col)
|
||||||
|
{
|
||||||
|
var arr = new Mass?[col.Count];
|
||||||
|
col.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (units is IReadOnlyCollection<PogonMass?> roc)
|
||||||
|
{
|
||||||
|
var arr = new Mass?[roc.Count];
|
||||||
|
roc.Multiply(multiplicator, arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
return MultiplyNullableIterator(units, multiplicator);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static IEnumerable<Mass> Multiply(
|
||||||
|
this Length multiplicator, IEnumerable<PogonMass> units) => Multiply(units, multiplicator);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static IEnumerable<Mass?> Multiply(
|
||||||
|
this Length multiplicator, IEnumerable<PogonMass?> units) => Multiply(units, multiplicator);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal static void MultiplyCore(this ReadOnlySpan<PogonMass> source, Length value, Span<Mass> destination)
|
internal static void MultiplyCore(this ReadOnlySpan<PogonMass> source, Length value, Span<Mass> destination)
|
||||||
{
|
{
|
||||||
var dVal = value._Value;
|
var dVal = value._Value;
|
||||||
int len = source.Length;
|
source.MultiplyCore(dVal, destination);
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<PogonMass, double>(source);
|
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<Mass, double>(destination);
|
|
||||||
|
|
||||||
var vectorized_Value = new Vector<double>(dVal);
|
|
||||||
int vectorSize = Vector<double>.Count;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
|
|
||||||
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
|
|
||||||
|
|
||||||
int SIMDEnd = len - (len % vectorSize);
|
|
||||||
for (; i < SIMDEnd; i += vectorSize)
|
|
||||||
{
|
|
||||||
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
|
|
||||||
ReadOnlySpan<double> srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize);
|
|
||||||
var vector = new Vector<double>(srcWindow);
|
|
||||||
var multiplied = vector * vectorized_Value;
|
|
||||||
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
|
|
||||||
Span<double> dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize);
|
|
||||||
multiplied.CopyTo(dstWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < len; i++)
|
|
||||||
{
|
|
||||||
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * dVal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
internal static void MultiplyCore(this ReadOnlySpan<Length> source, PogonMass value, Span<Mass> destination)
|
internal static void MultiplyCore(this ReadOnlySpan<Length> source, PogonMass value, Span<Mass> destination)
|
||||||
{
|
{
|
||||||
var dVal = value._Value;
|
var dVal = value._Value;
|
||||||
int len = source.Length;
|
source.Multiply(dVal, destination);
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<Length, double>(source);
|
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<Mass, double>(destination);
|
|
||||||
|
|
||||||
var vectorized_Value = new Vector<double>(dVal);
|
|
||||||
int vectorSize = Vector<double>.Count;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
|
|
||||||
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
|
|
||||||
|
|
||||||
int SIMDEnd = len - (len % vectorSize);
|
|
||||||
for (; i < SIMDEnd; i += vectorSize)
|
|
||||||
{
|
|
||||||
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
|
|
||||||
ReadOnlySpan<double> srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize);
|
|
||||||
var vector = new Vector<double>(srcWindow);
|
|
||||||
var multiplied = vector * vectorized_Value;
|
|
||||||
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
|
|
||||||
Span<double> dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize);
|
|
||||||
multiplied.CopyTo(dstWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < len; i++)
|
|
||||||
{
|
|
||||||
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * dVal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,28 +3,54 @@ namespace QWERTYkez.Mensura.Units.Pogon;
|
|||||||
|
|
||||||
public readonly partial record struct PogonMass
|
public readonly partial record struct PogonMass
|
||||||
{
|
{
|
||||||
|
public static PogonMass GramPerMilliMeter { get; } = new() { _PerMilliMeter = new() { Grams = 1 } };
|
||||||
|
public static PogonMass KiloGramPerMilliMeter { get; } = new() { _PerMilliMeter = new() { KiloGrams = 1 } };
|
||||||
|
public static PogonMass CentnerPerMilliMeter { get; } = new() { _PerMilliMeter = new() { Centners = 1 } };
|
||||||
|
public static PogonMass TonPerMilliMeter { get; } = new() { _PerMilliMeter = new() { Tons = 1 } };
|
||||||
[NotMapped, JsonIgnore] public Mass _PerMilliMeter
|
[NotMapped, JsonIgnore] public Mass _PerMilliMeter
|
||||||
{ get => (Mass)_Value; init => _Value = (double)value; }
|
{ get => (Mass)_Value; init => _Value = (double)value; }
|
||||||
|
|
||||||
|
|
||||||
|
public static PogonMass GramPerCentiMeter { get; } = new() { PerCentiMeter = new() { Grams = 1 } };
|
||||||
|
public static PogonMass KiloGramPerCentiMeter { get; } = new() { PerCentiMeter = new() { KiloGrams = 1 } };
|
||||||
|
public static PogonMass CentnerPerCentiMeter { get; } = new() { PerCentiMeter = new() { Centners = 1 } };
|
||||||
|
public static PogonMass TonPerCentiMeter { get; } = new() { PerCentiMeter = new() { Tons = 1 } };
|
||||||
[NotMapped, JsonIgnore] public Mass PerCentiMeter
|
[NotMapped, JsonIgnore] public Mass PerCentiMeter
|
||||||
{
|
{
|
||||||
get => new(_Value * LengthConv.CentiMeters.Multiplicator);
|
get => new(_Value * LengthConv.CentiMeters.Multiplicator);
|
||||||
init => _Value = value._Value / LengthConv.CentiMeters.Multiplicator;
|
init => _Value = value._Value / LengthConv.CentiMeters.Multiplicator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static PogonMass GramPerDeciMeter { get; } = new() { PerDeciMeter = new() { Grams = 1 } };
|
||||||
|
public static PogonMass KiloGramPerDeciMeter { get; } = new() { PerDeciMeter = new() { KiloGrams = 1 } };
|
||||||
|
public static PogonMass CentnerPerDeciMeter { get; } = new() { PerDeciMeter = new() { Centners = 1 } };
|
||||||
|
public static PogonMass TonPerDeciMeter { get; } = new() { PerDeciMeter = new() { Tons = 1 } };
|
||||||
|
|
||||||
[NotMapped, JsonIgnore] public Mass PerDeciMeter
|
[NotMapped, JsonIgnore] public Mass PerDeciMeter
|
||||||
{
|
{
|
||||||
get => new(_Value * LengthConv.DeciMeters.Multiplicator);
|
get => new(_Value * LengthConv.DeciMeters.Multiplicator);
|
||||||
init => _Value = value._Value / LengthConv.DeciMeters.Multiplicator;
|
init => _Value = value._Value / LengthConv.DeciMeters.Multiplicator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static PogonMass GramPerMeter { get; } = new() { PerMeter = new() { Grams = 1 } };
|
||||||
|
public static PogonMass KiloGramPerMeter { get; } = new() { PerMeter = new() { KiloGrams = 1 } };
|
||||||
|
public static PogonMass CentnerPerMeter { get; } = new() { PerMeter = new() { Centners = 1 } };
|
||||||
|
public static PogonMass TonPerMeter { get; } = new() { PerMeter = new() { Tons = 1 } };
|
||||||
|
|
||||||
[NotMapped, JsonIgnore] public Mass PerMeter
|
[NotMapped, JsonIgnore] public Mass PerMeter
|
||||||
{
|
{
|
||||||
get => new(_Value * LengthConv.Meters.Multiplicator);
|
get => new(_Value * LengthConv.Meters.Multiplicator);
|
||||||
init => _Value = value._Value / LengthConv.Meters.Multiplicator;
|
init => _Value = value._Value / LengthConv.Meters.Multiplicator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static PogonMass GramPerKiloMeter { get; } = new() { PerKiloMeter = new() { Grams = 1 } };
|
||||||
|
public static PogonMass KiloGramPerKiloMeter { get; } = new() { PerKiloMeter = new() { KiloGrams = 1 } };
|
||||||
|
public static PogonMass CentnerPerKiloMeter { get; } = new() { PerKiloMeter = new() { Centners = 1 } };
|
||||||
|
public static PogonMass TonPerKiloMeter { get; } = new() { PerKiloMeter = new() { Tons = 1 } };
|
||||||
|
|
||||||
[NotMapped, JsonIgnore] public Mass PerKiloMeter
|
[NotMapped, JsonIgnore] public Mass PerKiloMeter
|
||||||
{
|
{
|
||||||
get => new(_Value * LengthConv.KiloMeters.Multiplicator);
|
get => new(_Value * LengthConv.KiloMeters.Multiplicator);
|
||||||
|
|||||||
@@ -1,175 +1,175 @@
|
|||||||
namespace MetricSystem;
|
//namespace MetricSystem;
|
||||||
|
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// Base value is PerMilliMeterCubic
|
///// Base value is PerMilliMeterCubic
|
||||||
/// </summary>
|
///// </summary>
|
||||||
[Owned]
|
//[Owned]
|
||||||
public abstract class Udel<U, T> : Metric<U, Udel<U, T>>
|
//public abstract class Udel<U, T> : Metric<U, Udel<U, T>>
|
||||||
where U : Udel<U, T>, new()
|
// where U : Udel<U, T>, new()
|
||||||
where T : Metric<T, T>, new()
|
// where T : Metric<T, T>, new()
|
||||||
{
|
//{
|
||||||
protected override void OnValueChanged()
|
// protected override void OnValueChanged()
|
||||||
{
|
// {
|
||||||
OnPropertyChanged(nameof(PerMeter_PerMilliMeterSquared));
|
// OnPropertyChanged(nameof(PerMeter_PerMilliMeterSquared));
|
||||||
OnPropertyChanged(nameof(PerMilliMeterCubic));
|
// OnPropertyChanged(nameof(PerMilliMeterCubic));
|
||||||
OnPropertyChanged(nameof(PerCentiMeterCubic));
|
// OnPropertyChanged(nameof(PerCentiMeterCubic));
|
||||||
OnPropertyChanged(nameof(PerDeciMeterCubic));
|
// OnPropertyChanged(nameof(PerDeciMeterCubic));
|
||||||
OnPropertyChanged(nameof(PerMeterCubic));
|
// OnPropertyChanged(nameof(PerMeterCubic));
|
||||||
OnPropertyChanged(nameof(PerKiloMeterCubic));
|
// OnPropertyChanged(nameof(PerKiloMeterCubic));
|
||||||
}
|
// }
|
||||||
|
|
||||||
[NotMapped, JsonIgnore] internal T PerValue
|
// [NotMapped, JsonIgnore] internal T PerValue
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value,
|
// SilentValueSetter = Value,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value;
|
// Value = value.Value;
|
||||||
OnPropertyChanged(nameof(PerValue));
|
// OnPropertyChanged(nameof(PerValue));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T _PerMilliMeterCubic
|
// [NotMapped, JsonIgnore] public T _PerMilliMeterCubic
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value,
|
// SilentValueSetter = Value,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value;
|
// Value = value.Value;
|
||||||
OnPropertyChanged(nameof(_PerMilliMeterCubic));
|
// OnPropertyChanged(nameof(_PerMilliMeterCubic));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
[NotMapped, JsonIgnore] public T PerMilliMeterCubic
|
// [NotMapped, JsonIgnore] public T PerMilliMeterCubic
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value,
|
// SilentValueSetter = Value,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value;
|
// Value = value.Value;
|
||||||
OnPropertyChanged(nameof(PerMilliMeterCubic));
|
// OnPropertyChanged(nameof(PerMilliMeterCubic));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T PerMeter_PerMilliMeterSquared
|
// [NotMapped, JsonIgnore] public T PerMeter_PerMilliMeterSquared
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value * LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2),
|
// SilentValueSetter = Value * LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2),
|
||||||
BaseContainerMultiplicator = LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2),
|
// BaseContainerMultiplicator = LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2),
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value / (LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2));
|
// Value = value.Value / (LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2));
|
||||||
OnPropertyChanged(nameof(PerMeter_PerMilliMeterSquared));
|
// OnPropertyChanged(nameof(PerMeter_PerMilliMeterSquared));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T PerCentiMeterCubic
|
// [NotMapped, JsonIgnore] public T PerCentiMeterCubic
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value * Math.Pow(LengthConv.CentiMeters.Multiplicator, 3),
|
// SilentValueSetter = Value * Math.Pow(LengthConv.CentiMeters.Multiplicator, 3),
|
||||||
BaseContainerMultiplicator = Math.Pow(LengthConv.CentiMeters.Multiplicator, 3),
|
// BaseContainerMultiplicator = Math.Pow(LengthConv.CentiMeters.Multiplicator, 3),
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value / Math.Pow(LengthConv.CentiMeters.Multiplicator, 3);
|
// Value = value.Value / Math.Pow(LengthConv.CentiMeters.Multiplicator, 3);
|
||||||
OnPropertyChanged(nameof(PerCentiMeterCubic));
|
// OnPropertyChanged(nameof(PerCentiMeterCubic));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T PerDeciMeterCubic
|
// [NotMapped, JsonIgnore] public T PerDeciMeterCubic
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value * Math.Pow(LengthConv.DeciMeters.Multiplicator, 3),
|
// SilentValueSetter = Value * Math.Pow(LengthConv.DeciMeters.Multiplicator, 3),
|
||||||
BaseContainerMultiplicator = Math.Pow(LengthConv.DeciMeters.Multiplicator, 3),
|
// BaseContainerMultiplicator = Math.Pow(LengthConv.DeciMeters.Multiplicator, 3),
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value / Math.Pow(LengthConv.DeciMeters.Multiplicator, 3);
|
// Value = value.Value / Math.Pow(LengthConv.DeciMeters.Multiplicator, 3);
|
||||||
OnPropertyChanged(nameof(PerDeciMeterCubic));
|
// OnPropertyChanged(nameof(PerDeciMeterCubic));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T PerMeterCubic
|
// [NotMapped, JsonIgnore] public T PerMeterCubic
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value * Math.Pow(LengthConv.Meters.Multiplicator, 3),
|
// SilentValueSetter = Value * Math.Pow(LengthConv.Meters.Multiplicator, 3),
|
||||||
BaseContainerMultiplicator = Math.Pow(LengthConv.Meters.Multiplicator, 3),
|
// BaseContainerMultiplicator = Math.Pow(LengthConv.Meters.Multiplicator, 3),
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value / Math.Pow(LengthConv.Meters.Multiplicator, 3);
|
// Value = value.Value / Math.Pow(LengthConv.Meters.Multiplicator, 3);
|
||||||
OnPropertyChanged(nameof(PerMeterCubic));
|
// OnPropertyChanged(nameof(PerMeterCubic));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
[NotMapped, JsonIgnore] public T PerKiloMeterCubic
|
// [NotMapped, JsonIgnore] public T PerKiloMeterCubic
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
return new()
|
// return new()
|
||||||
{
|
// {
|
||||||
BaseContainer = this,
|
// BaseContainer = this,
|
||||||
SilentValueSetter = Value * Math.Pow(LengthConv.KiloMeters.Multiplicator, 3),
|
// SilentValueSetter = Value * Math.Pow(LengthConv.KiloMeters.Multiplicator, 3),
|
||||||
BaseContainerMultiplicator = Math.Pow(LengthConv.KiloMeters.Multiplicator, 3),
|
// BaseContainerMultiplicator = Math.Pow(LengthConv.KiloMeters.Multiplicator, 3),
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
Value = value.Value / Math.Pow(LengthConv.KiloMeters.Multiplicator, 3);
|
// Value = value.Value / Math.Pow(LengthConv.KiloMeters.Multiplicator, 3);
|
||||||
OnPropertyChanged(nameof(PerKiloMeterCubic));
|
// OnPropertyChanged(nameof(PerKiloMeterCubic));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
public static T operator *(Udel<U, T> left, Volume right) => ((U)left).Protect()._PerMilliMeterCubic * right.Protect()._MilliMetersCubic;
|
// public static T operator *(Udel<U, T> left, Volume right) => ((U)left).Protect()._PerMilliMeterCubic * right.Protect()._MilliMetersCubic;
|
||||||
public static MetricCollection<T> operator *(Udel<U, T> left, MetricCollection<Volume> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
// public static MetricCollection<T> operator *(Udel<U, T> left, MetricCollection<Volume> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
||||||
public static MetricArray<T> operator *(Udel<U, T> left, MetricArray<Volume> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
// public static MetricArray<T> operator *(Udel<U, T> left, MetricArray<Volume> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
||||||
public static MetricList<T> operator *(Udel<U, T> left, MetricList<Volume> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
// public static MetricList<T> operator *(Udel<U, T> left, MetricList<Volume> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
||||||
public static MetricObservableCollection<T> operator *(Udel<U, T> left, MetricObservableCollection<Volume> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
// public static MetricObservableCollection<T> operator *(Udel<U, T> left, MetricObservableCollection<Volume> right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect());
|
||||||
|
|
||||||
public static T operator *(Volume left, Udel<U, T> right) => ((U)right).Protect()._PerMilliMeterCubic * left.Protect()._MilliMetersCubic;
|
// public static T operator *(Volume left, Udel<U, T> right) => ((U)right).Protect()._PerMilliMeterCubic * left.Protect()._MilliMetersCubic;
|
||||||
public static MetricCollection<T> operator *(MetricCollection<Volume> left, Udel<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
// public static MetricCollection<T> operator *(MetricCollection<Volume> left, Udel<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
||||||
public static MetricArray<T> operator *(MetricArray<Volume> left, Udel<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
// public static MetricArray<T> operator *(MetricArray<Volume> left, Udel<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
||||||
public static MetricList<T> operator *(MetricList<Volume> left, Udel<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
// public static MetricList<T> operator *(MetricList<Volume> left, Udel<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
||||||
public static MetricObservableCollection<T> operator *(MetricObservableCollection<Volume> left, Udel<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
// public static MetricObservableCollection<T> operator *(MetricObservableCollection<Volume> left, Udel<U, T> right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect());
|
||||||
|
|
||||||
public static Volume operator /(T left, Udel<U, T> right) => new() { _MilliMetersCubic = left.Protect() / ((U)right).Protect()._PerMilliMeterCubic };
|
// public static Volume operator /(T left, Udel<U, T> right) => new() { _MilliMetersCubic = left.Protect() / ((U)right).Protect()._PerMilliMeterCubic };
|
||||||
public static MetricCollection<Volume> operator *(MetricCollection<T> left, Udel<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
// public static MetricCollection<Volume> operator *(MetricCollection<T> left, Udel<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
||||||
public static MetricArray<Volume> operator *(MetricArray<T> left, Udel<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
// public static MetricArray<Volume> operator *(MetricArray<T> left, Udel<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
||||||
public static MetricList<Volume> operator *(MetricList<T> left, Udel<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
// public static MetricList<Volume> operator *(MetricList<T> left, Udel<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
||||||
public static MetricObservableCollection<Volume> operator *(MetricObservableCollection<T> left, Udel<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
// public static MetricObservableCollection<Volume> operator *(MetricObservableCollection<T> left, Udel<U, T> right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect());
|
||||||
}
|
//}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
namespace MetricSystem;
|
//namespace MetricSystem;
|
||||||
|
|
||||||
[Owned, JsonConverter(typeof(MetricFormatter<UdelForce>)), DebuggerDisplay("N/(m*mm2) = {PerMeter_PerMilliMeterSquared._Newtons.ToString(\"0.###\")}, kgf/(m*mm2) = {PerMeter_PerMilliMeterSquared.KiloGramForces.ToString(\"0.###\")}")]
|
//[Owned, JsonConverter(typeof(MetricFormatter<UdelForce>)), DebuggerDisplay("N/(m*mm2) = {PerMeter_PerMilliMeterSquared._Newtons.ToString(\"0.###\")}, kgf/(m*mm2) = {PerMeter_PerMilliMeterSquared.KiloGramForces.ToString(\"0.###\")}")]
|
||||||
public partial class UdelForce : Udel<UdelForce, Force>
|
//public partial class UdelForce : Udel<UdelForce, Force>
|
||||||
{
|
//{
|
||||||
[CollectionsOperatorsGenerator] public static PogonForce operator *(Area left, UdelForce right) => right * left;
|
// [CollectionsOperatorsGenerator] public static PogonForce operator *(Area left, UdelForce right) => right * left;
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static PogonForce operator *(UdelForce left, Area right) => left.MultiplyProtected<UdelForce, Area, PogonForce>(right, PogonForceCoeff);
|
// [CollectionsOperatorsGenerator] public static PogonForce operator *(UdelForce left, Area right) => left.MultiplyProtected<UdelForce, Area, PogonForce>(right, PogonForceCoeff);
|
||||||
static readonly double PogonForceCoeff = Coefficients.MultiplyCoefficient<UdelForce, Area, PogonForce>(a => a._PerMilliMeterCubic.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeter.Value = 1);
|
// static readonly double PogonForceCoeff = Coefficients.MultiplyCoefficient<UdelForce, Area, PogonForce>(a => a._PerMilliMeterCubic.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeter.Value = 1);
|
||||||
}
|
//}
|
||||||
|
|
||||||
public partial class Volume : Metric<Volume, Volume>
|
//public partial class Volume : Metric<Volume, Volume>
|
||||||
{
|
//{
|
||||||
[CollectionsOperatorsGenerator] public static UdelForce operator /(Force left, Volume right) => left.DivideProtected<Force, Volume, UdelForce>(right, UdelForceCoeff);
|
// [CollectionsOperatorsGenerator] public static UdelForce operator /(Force left, Volume right) => left.DivideProtected<Force, Volume, UdelForce>(right, UdelForceCoeff);
|
||||||
static readonly double UdelForceCoeff = Coefficients.DivideCoefficient<Force, Volume, UdelForce>(a => a.Value = 1, b => b._MilliMetersCubic = 1, r => r._PerMilliMeterCubic.Value = 1);
|
// static readonly double UdelForceCoeff = Coefficients.DivideCoefficient<Force, Volume, UdelForce>(a => a.Value = 1, b => b._MilliMetersCubic = 1, r => r._PerMilliMeterCubic.Value = 1);
|
||||||
}
|
//}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
namespace MetricSystem;
|
//namespace MetricSystem;
|
||||||
|
|
||||||
[Owned, JsonConverter(typeof(MetricFormatter<Density>)), DebuggerDisplay("gr/(m*mm2) = {PerMeter_PerMilliMeterSquared._Grams.ToString(\"0.###\")}, kg/(m*mm2) = {PerMeter_PerMilliMeterSquared.KiloGrams.ToString(\"0.###\")}")]
|
//[Owned, JsonConverter(typeof(MetricFormatter<Density>)), DebuggerDisplay("gr/(m*mm2) = {PerMeter_PerMilliMeterSquared._Grams.ToString(\"0.###\")}, kg/(m*mm2) = {PerMeter_PerMilliMeterSquared.KiloGrams.ToString(\"0.###\")}")]
|
||||||
public partial class Density : Udel<Density, Mass>
|
//public partial class Density : Udel<Density, Mass>
|
||||||
{
|
//{
|
||||||
[CollectionsOperatorsGenerator] public static PogonMass operator *(Area left, Density right) => right * left;
|
// [CollectionsOperatorsGenerator] public static PogonMass operator *(Area left, Density right) => right * left;
|
||||||
|
|
||||||
[CollectionsOperatorsGenerator] public static PogonMass operator *(Density left, Area right) => left.MultiplyProtected<Density, Area, PogonMass>(right, PogonMassCoeff);
|
// [CollectionsOperatorsGenerator] public static PogonMass operator *(Density left, Area right) => left.MultiplyProtected<Density, Area, PogonMass>(right, PogonMassCoeff);
|
||||||
static readonly double PogonMassCoeff = Coefficients.MultiplyCoefficient<Density, Area, PogonMass>(a => a._PerMilliMeterCubic.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeter.Value = 1);
|
// static readonly double PogonMassCoeff = Coefficients.MultiplyCoefficient<Density, Area, PogonMass>(a => a._PerMilliMeterCubic.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeter.Value = 1);
|
||||||
}
|
//}
|
||||||
|
|
||||||
public partial class Volume : Metric<Volume, Volume>
|
//public partial class Volume : Metric<Volume, Volume>
|
||||||
{
|
//{
|
||||||
[CollectionsOperatorsGenerator] public static Density operator /(Mass left, Volume right) => left.DivideProtected<Mass, Volume, Density>(right, DensityCoeff);
|
// [CollectionsOperatorsGenerator] public static Density operator /(Mass left, Volume right) => left.DivideProtected<Mass, Volume, Density>(right, DensityCoeff);
|
||||||
static readonly double DensityCoeff = Coefficients.DivideCoefficient<Mass, Volume, Density>(a => a.Value = 1, b => b._MilliMetersCubic = 1, r => r._PerMilliMeterCubic.Value = 1);
|
// static readonly double DensityCoeff = Coefficients.DivideCoefficient<Mass, Volume, Density>(a => a.Value = 1, b => b._MilliMetersCubic = 1, r => r._PerMilliMeterCubic.Value = 1);
|
||||||
}
|
//}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
global using XXXXXXXXXXXXXXExtensions = QWERTYkez.Mensura.Units.XXXXXXXXXXXXXXExtensions;
|
||||||
global using XXXXXXXXXXXXXX = QWERTYkez.Mensura.Units.XXXXXXXXXXXXXX;
|
global using XXXXXXXXXXXXXX = QWERTYkez.Mensura.Units.XXXXXXXXXXXXXX;
|
||||||
|
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Units;
|
namespace QWERTYkez.Mensura.Units;
|
||||||
@@ -39,14 +41,13 @@ public readonly partial record struct XXXXXXXXXXXXXX : IMensuraUnit<XXXXXXXXXXXX
|
|||||||
public static XXXXXXXXXXXXXX NegativeInfinity { get; } = new(double.NegativeInfinity);
|
public static XXXXXXXXXXXXXX NegativeInfinity { get; } = new(double.NegativeInfinity);
|
||||||
public static XXXXXXXXXXXXXX PositiveInfinity { get; } = new(double.PositiveInfinity);
|
public static XXXXXXXXXXXXXX PositiveInfinity { get; } = new(double.PositiveInfinity);
|
||||||
|
|
||||||
|
public static bool operator ==(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => T1.Protected() == T2.Protected();
|
||||||
|
public static bool operator !=(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => T1.Protected() != T2.Protected();
|
||||||
|
|
||||||
public static bool operator ==(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) == (T2 is null ? 0d : T2.Value._Value);
|
public static bool operator <(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => T1.Protected() < T2.Protected();
|
||||||
public static bool operator !=(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) != (T2 is null ? 0d : T2.Value._Value);
|
public static bool operator <=(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => T1.Protected() <= T2.Protected();
|
||||||
|
public static bool operator >(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => T1.Protected() > T2.Protected();
|
||||||
public static bool operator <(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) < (T2 is null ? 0d : T2.Value._Value);
|
public static bool operator >=(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => T1.Protected() >= T2.Protected();
|
||||||
public static bool operator <=(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) <= (T2 is null ? 0d : T2.Value._Value);
|
|
||||||
public static bool operator >(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) > (T2 is null ? 0d : T2.Value._Value);
|
|
||||||
public static bool operator >=(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) >= (T2 is null ? 0d : T2.Value._Value);
|
|
||||||
|
|
||||||
|
|
||||||
public static XXXXXXXXXXXXXX operator +(XXXXXXXXXXXXXX T2) => new(+T2._Value);
|
public static XXXXXXXXXXXXXX operator +(XXXXXXXXXXXXXX T2) => new(+T2._Value);
|
||||||
@@ -191,4 +192,9 @@ public readonly partial record struct XXXXXXXXXXXXXX : IMensuraUnit<XXXXXXXXXXXX
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal R Sqrt_Internal<R>() where R : struct, IMensuraUnit, IEquatable<R> => Math.Sqrt(_Value).ToUnit<R>();
|
internal R Sqrt_Internal<R>() where R : struct, IMensuraUnit, IEquatable<R> => Math.Sqrt(_Value).ToUnit<R>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class XXXXXXXXXXXXXXExtensions
|
||||||
|
{
|
||||||
|
public static double Protected(this XXXXXXXXXXXXXX? unit) => unit is null ? 0d : unit.Value._Value;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user