This commit is contained in:
melekhin
2026-06-03 12:07:27 +07:00
parent 69f529c4fc
commit c27c2e0085
19 changed files with 2002 additions and 1713 deletions

View File

@@ -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);
} }

View File

@@ -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>

View File

@@ -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 public static void Divide<T>(this ICollection<T?> units, double divisor, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static ICollection<T?> Divide<T>(this ICollection<T?> units, double divisor)
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 public static void Divide<T>(this double dividend, ICollection<T> units, Span<T> destination)
{
ArrayPool<T?>.Shared.Return(sharedNullableArray);
}
}
public static ICollection<T> Divide<T>(this double dividend, ICollection<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;
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 public static void Divide<T>(this double dividend, ICollection<T?> units, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static ICollection<T?> Divide<T>(this double dividend, ICollection<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;
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>();
} }
} public static void Divide<T>(this IReadOnlyCollection<T?> units, double divisor, Span<T?> destination)
return resultArray;
}
finally
{
ArrayPool<T?>.Shared.Return(sharedNullableArray);
}
}
public static IReadOnlyCollection<T> Divide<T>(this double dividend, IReadOnlyCollection<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;
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 public static void Divide<T>(this double dividend, IReadOnlyCollection<T> units, Span<T> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static IReadOnlyCollection<T?> Divide<T>(this double dividend, IReadOnlyCollection<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;
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++)
{
T? item = sharedNullableArray[i];
if (item.HasValue)
{
ref var dst = ref resultArray[i];
dst = (dividend / item.Value.ToDouble()).ToUnit<T>();
} }
} public static void Divide<T>(this double dividend, IReadOnlyCollection<T?> units, Span<T?> destination)
return resultArray; where T : struct, IMensuraUnit, IEquatable<T>
}
finally
{ {
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) { dividend.Divide(array, destination); return; }
if (units is List<T?> list) { dividend.Divide(CollectionsMarshal.AsSpan(list), destination); return; }
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);
} }
} }

View File

@@ -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 public static void Minus<T>(this ICollection<T?> units, double subtrahend, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static ICollection<T?> Minus<T>(this ICollection<T?> units, double subtrahend)
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 public static void Minus<T>(this double minuend, ICollection<T> units, Span<T> destination)
{
ArrayPool<T?>.Shared.Return(sharedNullableArray);
}
}
public static ICollection<T> Minus<T>(this double minuend, ICollection<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;
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 public static void Minus<T>(this double minuend, ICollection<T?> units, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static ICollection<T?> Minus<T>(this double minuend, ICollection<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;
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 public static void Minus<T>(this IReadOnlyCollection<T?> units, double subtrahend, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static IReadOnlyCollection<T?> Minus<T>(this IReadOnlyCollection<T?> units, double subtrahend)
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>();
} }
} public static void Minus<T>(this double minuend, IReadOnlyCollection<T> units, Span<T> destination)
return resultArray;
}
finally
{
ArrayPool<T?>.Shared.Return(sharedNullableArray);
}
}
public static IReadOnlyCollection<T> Minus<T>(this double minuend, IReadOnlyCollection<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;
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 public static void Minus<T>(this double minuend, IReadOnlyCollection<T?> units, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static IReadOnlyCollection<T?> Minus<T>(this double minuend, IReadOnlyCollection<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;
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);
} }
} }

View File

@@ -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 public static void Multiply<T>(this ICollection<T?> units, double multiplicator, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static ICollection<T?> Multiply<T>(this ICollection<T?> units, double multiplicator)
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 public static void Multiply<T>(this IReadOnlyCollection<T?> units, double multiplicator, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static IReadOnlyCollection<T?> Multiply<T>(this IReadOnlyCollection<T?> units, double multiplicator)
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);
} }

View File

@@ -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 public static void Plus<T>(this ICollection<T?> units, double summand, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static ICollection<T?> Plus<T>(this ICollection<T?> units, double summand)
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 public static void Plus<T>(this IReadOnlyCollection<T?> units, double summand, Span<T?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static IReadOnlyCollection<T?> Plus<T>(this IReadOnlyCollection<T?> units, double summand)
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);
} }

View File

@@ -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 internal static void Pow<T, R>(this ICollection<T?> units, double power, Span<R?> destination)
{
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)
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); internal static void Pow<T, R>(this IReadOnlyCollection<T?> units, double power, Span<R?> destination)
return finalResult;
}
finally
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
internal static IReadOnlyCollection<R?> Pow<T, R>(this IReadOnlyCollection<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;
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);
} }
} }

View File

@@ -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 public static void Sqrt<T, R>(this ICollection<T?> units, Span<R?> destination)
{
ArrayPool<T>.Shared.Return(sharedArray);
}
}
public static ICollection<R?> Sqrt<T, R>(this ICollection<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;
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;
} }
return finalResult;
} // === IReadOnlyCollection<Length> ===
finally 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>
{ {
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);
} }
} }

View File

@@ -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
{ {

View File

@@ -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>
////{
////}

View File

@@ -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());
} //}

View File

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

View File

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

View File

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

View File

@@ -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);

View File

@@ -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());
} //}

View File

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

View File

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

View File

@@ -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