From c27c2e008577e753a46c816a42659a507ba34ffd Mon Sep 17 00:00:00 2001 From: melekhin Date: Wed, 3 Jun 2026 12:07:27 +0700 Subject: [PATCH] 26.06.03 --- .../UnitOperatorsGenerator.cs | 20 +- .../Extensions/CastExtensions.cs | 9 - .../Extensions/CollectionsDivideExtensions.cs | 480 ++++++++---------- .../Extensions/CollectionsMinusExtensions.cs | 465 ++++++++--------- .../CollectionsMultiplyExtensions.cs | 263 +++++----- .../Extensions/CollectionsPlusExtensions.cs | 268 +++++----- .../Extensions/CollectionsPowExtensions.cs | 373 +++++++------- .../Extensions/CollectionsSqrtExtensions.cs | 216 +++++--- QWERTYkez.Mensura/Extensions/ToDouble.cs | 4 +- QWERTYkez.Mensura/Operators.cs | 426 ++++++++-------- QWERTYkez.Mensura/Units/Pogon/.Pogon.cs | 264 +++++----- QWERTYkez.Mensura/Units/Pogon/PogonForce.cs | 20 +- QWERTYkez.Mensura/Units/Pogon/PogonMass.cs | 24 +- .../Units/Pogon/PogonXXXXXXXX.Gen.cs | 449 +++++++++++++--- .../Units/Pogon/PogonXXXXXXXX.Ref.cs | 28 +- QWERTYkez.Mensura/Units/Udel/.Udel.cs | 334 ++++++------ QWERTYkez.Mensura/Units/Udel/UdelForce.cs | 26 +- .../Units/Udel/UdelMass (Density).cs | 26 +- QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs | 20 +- 19 files changed, 2002 insertions(+), 1713 deletions(-) diff --git a/QWERTYkez.Mensura.Generator/UnitOperatorsGenerator.cs b/QWERTYkez.Mensura.Generator/UnitOperatorsGenerator.cs index db3af7d..e31148f 100644 --- a/QWERTYkez.Mensura.Generator/UnitOperatorsGenerator.cs +++ b/QWERTYkez.Mensura.Generator/UnitOperatorsGenerator.cs @@ -91,7 +91,9 @@ namespace QWERTYkez.Mensura // Вы должны скопировать сюда всё содержимое вашего второго файла, // заменив {typeName} на {typeName}. string skeleton = @" +global using {typeName}Extensions = QWERTYkez.Mensura.Units.{typeName}Extensions; global using {typeName} = QWERTYkez.Mensura.Units.{typeName}; + using System.Runtime.Serialization; 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} 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 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 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.Protected() < T2.Protected(); + 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.Protected() >= T2.Protected(); 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)] internal R Sqrt_Internal() where R : struct, IMensuraUnit, IEquatable => Math.Sqrt(_Value).ToUnit(); } + +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); } diff --git a/QWERTYkez.Mensura/Extensions/CastExtensions.cs b/QWERTYkez.Mensura/Extensions/CastExtensions.cs index ccf88df..0f81a68 100644 --- a/QWERTYkez.Mensura/Extensions/CastExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CastExtensions.cs @@ -11,15 +11,6 @@ public static partial class CastExtensions } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static double ToDouble(this T? unit) - where T : struct, IMensuraUnit, IEquatable - { - T actual = unit.GetValueOrDefault(); - return Unsafe.As(ref actual); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T ToUnit(this double val) where T : struct, IMensuraUnit, IEquatable diff --git a/QWERTYkez.Mensura/Extensions/CollectionsDivideExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsDivideExtensions.cs index 0b3fd15..2284e03 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsDivideExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsDivideExtensions.cs @@ -1,20 +1,14 @@ -using System.Buffers; - -namespace QWERTYkez.Mensura.Extensions; +namespace QWERTYkez.Mensura.Extensions; public static partial class CollectionsDivideExtensions { - // === ReadOnlySpan === SIMD - public static void Divide(this ReadOnlySpan units, double divisor, Span destination) + // === DivideCore === SIMD + internal static void DivideCore(this ReadOnlySpan units, double divisor, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); - Span dstDouble = MemoryMarshal.Cast(destination); + Span dstDouble = MemoryMarshal.Cast(destination); // Вместо деления в цикле, умножаем на обратное число (invDivisor) 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; } } - public static void Divide(this ReadOnlySpan units, double divisor, Span destination) + internal static void DivideCore(this ReadOnlySpan units, double divisor, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - - // Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов ref var srcRef = ref MemoryMarshal.GetReference(units); 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); // Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага) - d0 = u0.HasValue ? (u0.Value.ToDouble() * invDivisor).ToUnit() : null; - d1 = u1.HasValue ? (u1.Value.ToDouble() * invDivisor).ToUnit() : null; - d2 = u2.HasValue ? (u2.Value.ToDouble() * invDivisor).ToUnit() : null; - d3 = u3.HasValue ? (u3.Value.ToDouble() * invDivisor).ToUnit() : null; + d0 = u0.HasValue ? (u0.Value.ToDouble() * invDivisor).ToUnit() : null; + d1 = u1.HasValue ? (u1.Value.ToDouble() * invDivisor).ToUnit() : null; + d2 = u2.HasValue ? (u2.Value.ToDouble() * invDivisor).ToUnit() : null; + d3 = u3.HasValue ? (u3.Value.ToDouble() * invDivisor).ToUnit() : null; } // 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук) @@ -90,20 +79,16 @@ public static partial class CollectionsDivideExtensions T? unit = Unsafe.Add(ref srcRef, i); ref var dst = ref Unsafe.Add(ref dstRef, i); - dst = unit.HasValue ? (unit.Value.ToDouble() * invDivisor).ToUnit() : null; + dst = unit.HasValue ? (unit.Value.ToDouble() * invDivisor).ToUnit() : null; } } //SIMD - public static void Divide(this double dividend, ReadOnlySpan units, Span destination) + internal static void DivideCore(this double dividend, ReadOnlySpan units, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); - Span dstDouble = MemoryMarshal.Cast(destination); + Span dstDouble = MemoryMarshal.Cast(destination); var vectorizedDividend = new Vector(dividend); int vectorSize = Vector.Count; @@ -133,13 +118,10 @@ public static partial class CollectionsDivideExtensions Unsafe.Add(ref dstRef, i) = dividend / Unsafe.Add(ref srcRef, i); } } - public static void Divide(this double dividend, ReadOnlySpan units, Span destination) + internal static void DivideCore(this double dividend, ReadOnlySpan units, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - - int len = units.Length; - // Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов ref var srcRef = ref MemoryMarshal.GetReference(units); 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); // Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага) - d0 = u0.HasValue ? (dividend / u0.Value.ToDouble()).ToUnit() : null; - d1 = u1.HasValue ? (dividend / u1.Value.ToDouble()).ToUnit() : null; - d2 = u2.HasValue ? (dividend / u2.Value.ToDouble()).ToUnit() : null; - d3 = u3.HasValue ? (dividend / u3.Value.ToDouble()).ToUnit() : null; + d0 = u0.HasValue ? (dividend / u0.Value.ToDouble()).ToUnit() : null; + d1 = u1.HasValue ? (dividend / u1.Value.ToDouble()).ToUnit() : null; + d2 = u2.HasValue ? (dividend / u2.Value.ToDouble()).ToUnit() : null; + d3 = u3.HasValue ? (dividend / u3.Value.ToDouble()).ToUnit() : null; } // 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук) @@ -174,10 +156,56 @@ public static partial class CollectionsDivideExtensions T? unit = Unsafe.Add(ref srcRef, i); ref var dst = ref Unsafe.Add(ref dstRef, i); - dst = unit.HasValue ? (dividend / unit.Value.ToDouble()).ToUnit() : null; + dst = unit.HasValue ? (dividend / unit.Value.ToDouble()).ToUnit() : null; } } + + + + + // === ReadOnlySpan + public static void Divide(this ReadOnlySpan units, double divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this ReadOnlySpan units, double divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this double dividend, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this double dividend, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + if (units.IsEmpty) return; + int len = units.Length; + if (len > destination.Length) + throw new ArgumentException("Целевой буфер destination меньше исходного source."); + + dividend.DivideCore(units, len, destination); + } + // === Array === public static T[] Divide(this T[] units, double divisor) where T : struct, IMensuraUnit, IEquatable @@ -197,21 +225,8 @@ public static partial class CollectionsDivideExtensions int len = units.Length; if (len == 0) return []; - // Выделяем чистую память (0 аллокаций логики, только сам массив) var result = new T?[len]; - double invDivisor = 1.0 / divisor; - - 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(); - } - } + Divide(units, divisor, result); return result; } public static T[] Divide(this double dividend, T[] units) @@ -233,16 +248,7 @@ public static partial class CollectionsDivideExtensions if (len == 0) return []; var result = new T?[len]; - - 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(); - } - } + Divide(dividend, units, result); return result; } @@ -266,27 +272,17 @@ public static partial class CollectionsDivideExtensions if (count == 0) return []; var resultArray = new T?[count]; - double invDivisor = 1.0 / divisor; - ReadOnlySpan 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(); - } - } + Divide(CollectionsMarshal.AsSpan(units), divisor, resultArray); return resultArray.WrapAsList(); } public static List Divide(this double dividend, List units) where T : struct, IMensuraUnit, IEquatable { if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; + int count = units.Count; + if (count == 0) return []; - var resultArray = new T[len]; + var resultArray = new T[count]; Divide(dividend, CollectionsMarshal.AsSpan(units), resultArray); return resultArray.WrapAsList(); } @@ -298,220 +294,148 @@ public static partial class CollectionsDivideExtensions if (count == 0) return []; var resultArray = new T?[count]; - ReadOnlySpan 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 = (dividend / item.Value.ToDouble()).ToUnit(); - } - } + Divide(dividend, CollectionsMarshal.AsSpan(units), resultArray); return resultArray.WrapAsList(); } // === ICollection === - public static ICollection Divide(this ICollection units, double divisor) + public static void Divide(this ICollection units, double divisor, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Divide(divisor); - if (units is List list) return list.Divide(divisor); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - units.CopyTo(sharedArray, 0); - Divide(new ReadOnlySpan(sharedArray, 0, count), divisor, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { array.Divide(divisor, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Divide(divisor, destination); return; } + + int i = 0; + double invDivisor = 1.0 / divisor; + foreach (var item in units) + destination[i++] = (item.ToDouble() * invDivisor).ToUnit(); } - public static ICollection Divide(this ICollection units, double divisor) + public static void Divide(this ICollection units, double divisor, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return array.Divide(divisor); - if (units is List list) return list.Divide(divisor); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - var resultArray = new T?[count]; - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - try - { - units.CopyTo(sharedNullableArray, 0); - var srcSpan = new ReadOnlySpan(sharedNullableArray, 0, count); - srcSpan.Divide(divisor, resultArray); - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { array.Divide(divisor, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Divide(divisor, destination); return; } + + int i = 0; + double invDivisor = 1.0 / divisor; + foreach (var item in units) + destination[i++] = item.HasValue + ? (item.Value.ToDouble() * invDivisor).ToUnit() : null; } - public static ICollection Divide(this double dividend, ICollection units) + public static void Divide(this double dividend, ICollection units, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return dividend.Divide(array); - if (units is List list) return dividend.Divide(list); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - units.CopyTo(sharedArray, 0); - Divide(dividend, new ReadOnlySpan(sharedArray, 0, count), finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { dividend.Divide(array, destination); return; } + if (units is List list) { dividend.Divide(CollectionsMarshal.AsSpan(list), destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (dividend / item.ToDouble()).ToUnit(); } - public static ICollection Divide(this double dividend, ICollection units) + public static void Divide(this double dividend, ICollection units, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return dividend.Divide(array); - if (units is List list) return dividend.Divide(list); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - var resultArray = new T?[count]; - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - try - { - units.CopyTo(sharedNullableArray, 0); - var srcSpan = new ReadOnlySpan(sharedNullableArray, 0, count); - dividend.Divide(srcSpan, resultArray); - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { dividend.Divide(array, destination); return; } + if (units is List 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() : null; } // === IReadOnlyCollection === - public static IReadOnlyCollection Divide(this IReadOnlyCollection units, double divisor) + public static void Divide(this IReadOnlyCollection units, double divisor, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Divide(divisor); - if (units is List list) return list.Divide(divisor); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - int index = 0; - foreach (var item in units) sharedArray[index++] = item; - Divide(sharedArray, divisor, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } - } - public static IReadOnlyCollection Divide(this IReadOnlyCollection units, double divisor) - where T : struct, IMensuraUnit, IEquatable - { - 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 list) return list.Divide(divisor); + if (units is T[] array) { array.Divide(divisor, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Divide(divisor, destination); return; } - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - var resultArray = new T?[count]; + int i = 0; double invDivisor = 1.0 / divisor; - try - { - 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(); - } - } - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + foreach (var item in units) + destination[i++] = (item.ToDouble() * invDivisor).ToUnit(); } - public static IReadOnlyCollection Divide(this double dividend, IReadOnlyCollection units) + public static void Divide(this IReadOnlyCollection units, double divisor, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Divide(dividend); - if (units is List list) return list.Divide(dividend); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - int index = 0; - foreach (var item in units) sharedArray[index++] = item; - Divide(dividend, sharedArray, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T?[] array) { array.Divide(divisor, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Divide(divisor, destination); return; } + + int i = 0; + double invDivisor = 1.0 / divisor; + foreach (var item in units) + destination[i++] = item.HasValue + ? (item.Value.ToDouble() * invDivisor).ToUnit() : null; } - public static IReadOnlyCollection Divide(this double dividend, IReadOnlyCollection units) + public static void Divide(this double dividend, IReadOnlyCollection units, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return array.Divide(dividend); - if (units is List list) return list.Divide(dividend); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - var resultArray = new T?[count]; - try - { - 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 = (dividend / item.Value.ToDouble()).ToUnit(); - } - } - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T[] array) { dividend.Divide(array, destination); return; } + if (units is List list) { dividend.Divide(CollectionsMarshal.AsSpan(list), destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (dividend / item.ToDouble()).ToUnit(); + } + public static void Divide(this double dividend, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return; + int count = units.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (units is T?[] array) { dividend.Divide(array, destination); return; } + if (units is List 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() : null; } // === IEnumerable + yeild === @@ -551,8 +475,18 @@ public static partial class CollectionsDivideExtensions if (units is null) return null!; if (units is T[] array) return array.Divide(divisor); if (units is List list) return list.Divide(divisor); - if (units is ICollection col) return col.Divide(divisor); - if (units is IReadOnlyCollection roc) return roc.Divide(divisor); + if (units is ICollection col) + { + var arr = new T[col.Count]; + col.Divide(divisor, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T[roc.Count]; + roc.Divide(divisor, arr); + return arr; + } return DivideIterator(units, divisor); } public static IEnumerable Divide(this IEnumerable units, double divisor) @@ -561,8 +495,18 @@ public static partial class CollectionsDivideExtensions if (units is null) return null!; if (units is T?[] array) return array.Divide(divisor); if (units is List list) return list.Divide(divisor); - if (units is ICollection col) return col.Divide(divisor); - if (units is IReadOnlyCollection roc) return roc.Divide(divisor); + if (units is ICollection col) + { + var arr = new T?[col.Count]; + col.Divide(divisor, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T?[roc.Count]; + roc.Divide(divisor, arr); + return arr; + } return DivideNullableIterator(units, divisor); } public static IEnumerable Divide(this double dividend, IEnumerable units) @@ -571,8 +515,18 @@ public static partial class CollectionsDivideExtensions if (units is null) return null!; if (units is T[] array) return dividend.Divide(array); if (units is List list) return dividend.Divide(list); - if (units is ICollection col) return dividend.Divide(col); - if (units is IReadOnlyCollection roc) return dividend.Divide(roc); + if (units is ICollection col) + { + var arr = new T[col.Count]; + dividend.Divide(col, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T[roc.Count]; + dividend.Divide(roc, arr); + return arr; + } return DivideIterator(dividend, units); } public static IEnumerable Divide(this double dividend, IEnumerable units) @@ -581,8 +535,18 @@ public static partial class CollectionsDivideExtensions if (units is null) return null!; if (units is T?[] array) return dividend.Divide(array); if (units is List list) return dividend.Divide(list); - if (units is ICollection col) return dividend.Divide(col); - if (units is IReadOnlyCollection roc) return dividend.Divide(roc); + if (units is ICollection col) + { + var arr = new T?[col.Count]; + dividend.Divide(col, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T?[roc.Count]; + dividend.Divide(roc, arr); + return arr; + } return DivideNullableIterator(dividend, units); } } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Extensions/CollectionsMinusExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsMinusExtensions.cs index 9751e7b..5099295 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsMinusExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsMinusExtensions.cs @@ -1,20 +1,14 @@ -using System.Buffers; - -namespace QWERTYkez.Mensura.Extensions; +namespace QWERTYkez.Mensura.Extensions; public static partial class CollectionsMinusExtensions { - // === ReadOnlySpan === SIMD - public static void Minus(this ReadOnlySpan units, double subtrahend, Span destination) + // === MinusCore === SIMD + internal static void MinusCore(this ReadOnlySpan units, double subtrahend, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); - Span dstDouble = MemoryMarshal.Cast(destination); + Span dstDouble = MemoryMarshal.Cast(destination); var vectorizedSubtrahend = new Vector(subtrahend); int vectorSize = Vector.Count; @@ -42,13 +36,10 @@ public static partial class CollectionsMinusExtensions Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend; } } - public static void Minus(this ReadOnlySpan units, double subtrahend, Span destination) + internal static void MinusCore(this ReadOnlySpan units, double subtrahend, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - - int len = units.Length; - // Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов ref var srcRef = ref MemoryMarshal.GetReference(units); 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); // Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага) - d0 = u0.HasValue ? (u0.Value.ToDouble() - subtrahend).ToUnit() : null; - d1 = u1.HasValue ? (u1.Value.ToDouble() - subtrahend).ToUnit() : null; - d2 = u2.HasValue ? (u2.Value.ToDouble() - subtrahend).ToUnit() : null; - d3 = u3.HasValue ? (u3.Value.ToDouble() - subtrahend).ToUnit() : null; + d0 = u0.HasValue ? (u0.Value.ToDouble() - subtrahend).ToUnit() : null; + d1 = u1.HasValue ? (u1.Value.ToDouble() - subtrahend).ToUnit() : null; + d2 = u2.HasValue ? (u2.Value.ToDouble() - subtrahend).ToUnit() : null; + d3 = u3.HasValue ? (u3.Value.ToDouble() - subtrahend).ToUnit() : null; } // 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук) @@ -83,20 +74,16 @@ public static partial class CollectionsMinusExtensions T? unit = Unsafe.Add(ref srcRef, i); ref var dst = ref Unsafe.Add(ref dstRef, i); - dst = unit.HasValue ? (unit.Value.ToDouble() - subtrahend).ToUnit() : null; + dst = unit.HasValue ? (unit.Value.ToDouble() - subtrahend).ToUnit() : null; } } //SIMD - public static void Minus(this double minuend, ReadOnlySpan units, Span destination) + internal static void MinusCore(this double minuend, ReadOnlySpan units, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); - Span dstDouble = MemoryMarshal.Cast(destination); + Span dstDouble = MemoryMarshal.Cast(destination); var vectorizedMinuend = new Vector(minuend); int vectorSize = Vector.Count; @@ -126,13 +113,10 @@ public static partial class CollectionsMinusExtensions Unsafe.Add(ref dstRef, i) = minuend - Unsafe.Add(ref srcRef, i); } } - public static void Minus(this double minuend, ReadOnlySpan units, Span destination) + internal static void MinusCore(this double minuend, ReadOnlySpan units, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - - int len = units.Length; - // Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов ref var srcRef = ref MemoryMarshal.GetReference(units); 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); // Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага) - d0 = u0.HasValue ? (minuend - u0.Value.ToDouble()).ToUnit() : null; - d1 = u1.HasValue ? (minuend - u1.Value.ToDouble()).ToUnit() : null; - d2 = u2.HasValue ? (minuend - u2.Value.ToDouble()).ToUnit() : null; - d3 = u3.HasValue ? (minuend - u3.Value.ToDouble()).ToUnit() : null; + d0 = u0.HasValue ? (minuend - u0.Value.ToDouble()).ToUnit() : null; + d1 = u1.HasValue ? (minuend - u1.Value.ToDouble()).ToUnit() : null; + d2 = u2.HasValue ? (minuend - u2.Value.ToDouble()).ToUnit() : null; + d3 = u3.HasValue ? (minuend - u3.Value.ToDouble()).ToUnit() : null; } // 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук) @@ -167,10 +151,57 @@ public static partial class CollectionsMinusExtensions T? unit = Unsafe.Add(ref srcRef, i); ref var dst = ref Unsafe.Add(ref dstRef, i); - dst = unit.HasValue ? (minuend - unit.Value.ToDouble()).ToUnit() : null; + dst = unit.HasValue ? (minuend - unit.Value.ToDouble()).ToUnit() : null; } } + + + + + // === ReadOnlySpan + public static void Minus(this ReadOnlySpan units, double subtrahend, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this ReadOnlySpan units, double subtrahend, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this double minuend, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this double minuend, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + if (units.IsEmpty) return; + int len = units.Length; + if (len > destination.Length) + throw new ArgumentException("Целевой буфер destination меньше исходного source."); + + minuend.MinusCore(units, len, destination); + } + // === Array === public static T[] Minus(this T[] units, double subtrahend) where T : struct, IMensuraUnit, IEquatable @@ -190,19 +221,8 @@ public static partial class CollectionsMinusExtensions int len = units.Length; if (len == 0) return []; - // Выделяем чистую память (0 аллокаций логики, только сам массив) var result = new T?[len]; - 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() - subtrahend).ToUnit(); - } - } + Minus(units, subtrahend, result); return result; } public static T[] Minus(this double minuend, T[] units) @@ -224,16 +244,7 @@ public static partial class CollectionsMinusExtensions if (len == 0) return []; var result = new T?[len]; - - 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(); - } - } + Minus(minuend, units, result); return result; } @@ -257,26 +268,17 @@ public static partial class CollectionsMinusExtensions if (count == 0) return []; var resultArray = new T?[count]; - ReadOnlySpan 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() - subtrahend).ToUnit(); - } - } + Minus(CollectionsMarshal.AsSpan(units), subtrahend, resultArray); return resultArray.WrapAsList(); } public static List Minus(this double minuend, List units) where T : struct, IMensuraUnit, IEquatable { if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; + int count = units.Count; + if (count == 0) return []; - var resultArray = new T[len]; + var resultArray = new T[count]; Minus(minuend, CollectionsMarshal.AsSpan(units), resultArray); return resultArray.WrapAsList(); } @@ -288,219 +290,144 @@ public static partial class CollectionsMinusExtensions if (count == 0) return []; var resultArray = new T?[count]; - ReadOnlySpan 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 = (minuend - item.Value.ToDouble()).ToUnit(); - } - } + Minus(minuend, CollectionsMarshal.AsSpan(units), resultArray); return resultArray.WrapAsList(); } // === ICollection === - public static ICollection Minus(this ICollection units, double subtrahend) + public static void Minus(this ICollection units, double subtrahend, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Minus(subtrahend); - if (units is List list) return list.Minus(subtrahend); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - units.CopyTo(sharedArray, 0); - Minus(new ReadOnlySpan(sharedArray, 0, count), subtrahend, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { array.Minus(subtrahend, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (item.ToDouble() - subtrahend).ToUnit(); } - public static ICollection Minus(this ICollection units, double subtrahend) + public static void Minus(this ICollection units, double subtrahend, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return array.Minus(subtrahend); - if (units is List list) return list.Minus(subtrahend); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - var resultArray = new T?[count]; - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - try - { - units.CopyTo(sharedNullableArray, 0); - var srcSpan = new ReadOnlySpan(sharedNullableArray, 0, count); - srcSpan.Minus(subtrahend, resultArray); - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { array.Minus(subtrahend, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = item.HasValue + ? (item.Value.ToDouble() - subtrahend).ToUnit() : null; } - public static ICollection Minus(this double minuend, ICollection units) + public static void Minus(this double minuend, ICollection units, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return minuend.Minus(array); - if (units is List list) return minuend.Minus(list); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - units.CopyTo(sharedArray, 0); - Minus(minuend, new ReadOnlySpan(sharedArray, 0, count), finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { minuend.Minus(array, destination); return; } + if (units is List list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (minuend - item.ToDouble()).ToUnit(); } - public static ICollection Minus(this double minuend, ICollection units) + public static void Minus(this double minuend, ICollection units, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return minuend.Minus(array); - if (units is List list) return minuend.Minus(list); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - var resultArray = new T?[count]; - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - try - { - units.CopyTo(sharedNullableArray, 0); - var srcSpan = new ReadOnlySpan(sharedNullableArray, 0, count); - minuend.Minus(srcSpan, resultArray); - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { minuend.Minus(array, destination); return; } + if (units is List list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = item.HasValue + ? (minuend - item.Value.ToDouble()).ToUnit() : null; } // === IReadOnlyCollection === - public static IReadOnlyCollection Minus(this IReadOnlyCollection units, double subtrahend) + public static void Minus(this IReadOnlyCollection units, double subtrahend, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Minus(subtrahend); - if (units is List list) return list.Minus(subtrahend); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - int index = 0; - foreach (var item in units) sharedArray[index++] = item; - Minus(sharedArray, subtrahend, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { array.Minus(subtrahend, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (item.ToDouble() - subtrahend).ToUnit(); } - public static IReadOnlyCollection Minus(this IReadOnlyCollection units, double subtrahend) + public static void Minus(this IReadOnlyCollection units, double subtrahend, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return array.Minus(subtrahend); - if (units is List list) return list.Minus(subtrahend); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - var resultArray = new T?[count]; - try - { - 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() - subtrahend).ToUnit(); - } - } - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { array.Minus(subtrahend, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = item.HasValue + ? (item.Value.ToDouble() - subtrahend).ToUnit() : null; } - public static IReadOnlyCollection Minus(this double minuend, IReadOnlyCollection units) + public static void Minus(this double minuend, IReadOnlyCollection units, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Minus(minuend); - if (units is List list) return list.Minus(minuend); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - int index = 0; - foreach (var item in units) sharedArray[index++] = item; - Minus(minuend, sharedArray, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { minuend.Minus(array, destination); return; } + if (units is List list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (minuend - item.ToDouble()).ToUnit(); } - public static IReadOnlyCollection Minus(this double minuend, IReadOnlyCollection units) + public static void Minus(this double minuend, IReadOnlyCollection units, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return array.Minus(minuend); - if (units is List list) return list.Minus(minuend); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - var resultArray = new T?[count]; - try - { - 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 = (minuend - item.Value.ToDouble()).ToUnit(); - } - } - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { minuend.Minus(array, destination); return; } + if (units is List list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = item.HasValue + ? (minuend - item.Value.ToDouble()).ToUnit() : null; } // === IEnumerable + yeild === @@ -538,8 +465,18 @@ public static partial class CollectionsMinusExtensions if (units is null) return null!; if (units is T[] array) return array.Minus(subtrahend); if (units is List list) return list.Minus(subtrahend); - if (units is ICollection col) return col.Minus(subtrahend); - if (units is IReadOnlyCollection roc) return roc.Minus(subtrahend); + if (units is ICollection col) + { + var arr = new T[col.Count]; + col.Minus(subtrahend, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T[roc.Count]; + roc.Minus(subtrahend, arr); + return arr; + } return MinusIterator(units, subtrahend); } public static IEnumerable Minus(this IEnumerable units, double subtrahend) @@ -548,8 +485,18 @@ public static partial class CollectionsMinusExtensions if (units is null) return null!; if (units is T?[] array) return array.Minus(subtrahend); if (units is List list) return list.Minus(subtrahend); - if (units is ICollection col) return col.Minus(subtrahend); - if (units is IReadOnlyCollection roc) return roc.Minus(subtrahend); + if (units is ICollection col) + { + var arr = new T?[col.Count]; + col.Minus(subtrahend, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T?[roc.Count]; + roc.Minus(subtrahend, arr); + return arr; + } return MinusNullableIterator(units, subtrahend); } public static IEnumerable Minus(this double minuend, IEnumerable units) @@ -558,8 +505,18 @@ public static partial class CollectionsMinusExtensions if (units is null) return null!; if (units is T[] array) return minuend.Minus(array); if (units is List list) return minuend.Minus(list); - if (units is ICollection col) return minuend.Minus(col); - if (units is IReadOnlyCollection roc) return minuend.Minus(roc); + if (units is ICollection col) + { + var arr = new T[col.Count]; + minuend.Minus(col, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T[roc.Count]; + minuend.Minus(roc, arr); + return arr; + } return MinusIterator(minuend, units); } public static IEnumerable Minus(this double minuend, IEnumerable units) @@ -568,8 +525,18 @@ public static partial class CollectionsMinusExtensions if (units is null) return null!; if (units is T?[] array) return minuend.Minus(array); if (units is List list) return minuend.Minus(list); - if (units is ICollection col) return minuend.Minus(col); - if (units is IReadOnlyCollection roc) return minuend.Minus(roc); + if (units is ICollection col) + { + var arr = new T?[col.Count]; + minuend.Minus(col, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T?[roc.Count]; + minuend.Minus(roc, arr); + return arr; + } return MinusNullableIterator(minuend, units); } } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Extensions/CollectionsMultiplyExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsMultiplyExtensions.cs index 7850e6f..0c2a014 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsMultiplyExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsMultiplyExtensions.cs @@ -1,20 +1,14 @@ -using System.Buffers; - -namespace QWERTYkez.Mensura.Extensions; +namespace QWERTYkez.Mensura.Extensions; public static partial class CollectionsMultiplyExtensions { - // === ReadOnlySpan === SIMD - public static void Multiply(this ReadOnlySpan units, double multiplicator, Span destination) + // === MultiplyCore === SIMD + internal static void MultiplyCore(this ReadOnlySpan units, double multiplicator, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); - Span dstDouble = MemoryMarshal.Cast(destination); + Span dstDouble = MemoryMarshal.Cast(destination); var vectorizedMultiplicator = new Vector(multiplicator); int vectorSize = Vector.Count; @@ -41,14 +35,10 @@ public static partial class CollectionsMultiplyExtensions Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator; } } - public static void Multiply(this ReadOnlySpan units, double multiplicator, Span destination) + internal static void MultiplyCore(this ReadOnlySpan units, double multiplicator, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - // Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов ref var srcRef = ref MemoryMarshal.GetReference(units); 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); // Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага) - d0 = u0.HasValue ? (u0.Value.ToDouble() * multiplicator).ToUnit() : null; - d1 = u1.HasValue ? (u1.Value.ToDouble() * multiplicator).ToUnit() : null; - d2 = u2.HasValue ? (u2.Value.ToDouble() * multiplicator).ToUnit() : null; - d3 = u3.HasValue ? (u3.Value.ToDouble() * multiplicator).ToUnit() : null; + d0 = u0.HasValue ? (u0.Value.ToDouble() * multiplicator).ToUnit() : null; + d1 = u1.HasValue ? (u1.Value.ToDouble() * multiplicator).ToUnit() : null; + d2 = u2.HasValue ? (u2.Value.ToDouble() * multiplicator).ToUnit() : null; + d3 = u3.HasValue ? (u3.Value.ToDouble() * multiplicator).ToUnit() : null; } // 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук) @@ -83,10 +73,45 @@ public static partial class CollectionsMultiplyExtensions T? unit = Unsafe.Add(ref srcRef, i); ref var dst = ref Unsafe.Add(ref dstRef, i); - dst = unit.HasValue ? (unit.Value.ToDouble() * multiplicator).ToUnit() : null; + dst = unit.HasValue ? (unit.Value.ToDouble() * multiplicator).ToUnit() : null; } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void MultiplyCore(this double multiplicator, ReadOnlySpan units, int len, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable => units.MultiplyCore(multiplicator, len, destination); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void MultiplyCore(this double multiplicator, ReadOnlySpan units, int len, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable => units.MultiplyCore(multiplicator, len, destination); + + + + + // === ReadOnlySpan + public static void Multiply(this ReadOnlySpan units, double multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this ReadOnlySpan units, double multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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)] public static void Multiply(this double multiplicator, ReadOnlySpan units, Span destination) where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator, destination); @@ -114,20 +139,8 @@ public static partial class CollectionsMultiplyExtensions int len = units.Length; if (len == 0) return []; - // Выделяем чистую память (0 аллокаций логики, только сам массив) var result = new T?[len]; - - 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(); - } - } + Multiply(units, multiplicator, result); return result; } @@ -159,16 +172,7 @@ public static partial class CollectionsMultiplyExtensions if (count == 0) return []; var resultArray = new T?[count]; - ReadOnlySpan 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() * multiplicator).ToUnit(); - } - } + Multiply(CollectionsMarshal.AsSpan(units), multiplicator, resultArray); return resultArray.WrapAsList(); } @@ -181,123 +185,90 @@ public static partial class CollectionsMultiplyExtensions where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator); // === ICollection === - public static ICollection Multiply(this ICollection units, double multiplicator) + public static void Multiply(this ICollection units, double multiplicator, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Multiply(multiplicator); - if (units is List list) return list.Multiply(multiplicator); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - units.CopyTo(sharedArray, 0); - Multiply(new ReadOnlySpan(sharedArray, 0, count), multiplicator, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { array.Multiply(multiplicator, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (item.ToDouble() * multiplicator).ToUnit(); } - public static ICollection Multiply(this ICollection units, double multiplicator) + public static void Multiply(this ICollection units, double multiplicator, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return array.Multiply(multiplicator); - if (units is List list) return list.Multiply(multiplicator); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - var resultArray = new T?[count]; - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - try - { - units.CopyTo(sharedNullableArray, 0); - var srcSpan = new ReadOnlySpan(sharedNullableArray, 0, count); - srcSpan.Multiply(multiplicator, resultArray); - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { array.Multiply(multiplicator, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = item.HasValue + ? (item.Value.ToDouble() * multiplicator).ToUnit() : null; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ICollection Multiply(this double multiplicator, ICollection units) - where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator); + public static void Multiply(this double multiplicator, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator, destination); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ICollection Multiply(this double multiplicator, ICollection units) - where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator); + public static void Multiply(this double multiplicator, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator, destination); // === IReadOnlyCollection === - public static IReadOnlyCollection Multiply(this IReadOnlyCollection units, double multiplicator) + public static void Multiply(this IReadOnlyCollection units, double multiplicator, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Multiply(multiplicator); - if (units is List list) return list.Multiply(multiplicator); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - int index = 0; - foreach (var item in units) sharedArray[index++] = item; - Multiply(sharedArray, multiplicator, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { array.Multiply(multiplicator, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (item.ToDouble() * multiplicator).ToUnit(); } - public static IReadOnlyCollection Multiply(this IReadOnlyCollection units, double multiplicator) + public static void Multiply(this IReadOnlyCollection units, double multiplicator, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return array.Multiply(multiplicator); - if (units is List list) return list.Multiply(multiplicator); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - var resultArray = new T?[count]; - try - { - 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() * multiplicator).ToUnit(); - } - } - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { array.Multiply(multiplicator, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = item.HasValue + ? (item.Value.ToDouble() * multiplicator).ToUnit() : null; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static IReadOnlyCollection Multiply(this double multiplicator, IReadOnlyCollection units) - where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator); + public static void Multiply(this double multiplicator, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator, destination); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static IReadOnlyCollection Multiply(this double multiplicator, IReadOnlyCollection units) - where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator); + public static void Multiply(this double multiplicator, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Multiply(multiplicator, destination); // === IEnumerable + yeild === static IEnumerable MultiplyIterator(IEnumerable units, double multiplicator) @@ -321,8 +292,18 @@ public static partial class CollectionsMultiplyExtensions if (units is null) return null!; if (units is T[] array) return array.Multiply(multiplicator); if (units is List list) return list.Multiply(multiplicator); - if (units is ICollection col) return col.Multiply(multiplicator); - if (units is IReadOnlyCollection roc) return roc.Multiply(multiplicator); + if (units is ICollection col) + { + var arr = new T[col.Count]; + col.Multiply(multiplicator, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T[roc.Count]; + roc.Multiply(multiplicator, arr); + return arr; + } return MultiplyIterator(units, multiplicator); } public static IEnumerable Multiply(this IEnumerable units, double multiplicator) @@ -331,8 +312,18 @@ public static partial class CollectionsMultiplyExtensions if (units is null) return null!; if (units is T?[] array) return array.Multiply(multiplicator); if (units is List list) return list.Multiply(multiplicator); - if (units is ICollection col) return col.Multiply(multiplicator); - if (units is IReadOnlyCollection roc) return roc.Multiply(multiplicator); + if (units is ICollection col) + { + var arr = new T?[col.Count]; + col.Multiply(multiplicator, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T?[roc.Count]; + roc.Multiply(multiplicator, arr); + return arr; + } return MultiplyNullableIterator(units, multiplicator); } diff --git a/QWERTYkez.Mensura/Extensions/CollectionsPlusExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsPlusExtensions.cs index 62ac481..c050416 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsPlusExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsPlusExtensions.cs @@ -1,20 +1,14 @@ -using System.Buffers; - -namespace QWERTYkez.Mensura.Extensions; +namespace QWERTYkez.Mensura.Extensions; public static partial class CollectionsPlusExtensions { // === ReadOnlySpan === SIMD - public static void Plus(this ReadOnlySpan units, double summand, Span destination) + internal static void PlusCore(this ReadOnlySpan units, double summand, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); - Span dstDouble = MemoryMarshal.Cast(destination); + Span dstDouble = MemoryMarshal.Cast(destination); var vectorizedSummand = new Vector(summand); int vectorSize = Vector.Count; @@ -42,13 +36,10 @@ public static partial class CollectionsPlusExtensions Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand; } } - public static void Plus(this ReadOnlySpan units, double summand, Span destination) + internal static void PlusCore(this ReadOnlySpan units, double summand, int len, Span destination) where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - - int len = units.Length; - // Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов ref var srcRef = ref MemoryMarshal.GetReference(units); 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); // Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага) - d0 = u0.HasValue ? (u0.Value.ToDouble() + summand).ToUnit() : null; - d1 = u1.HasValue ? (u1.Value.ToDouble() + summand).ToUnit() : null; - d2 = u2.HasValue ? (u2.Value.ToDouble() + summand).ToUnit() : null; - d3 = u3.HasValue ? (u3.Value.ToDouble() + summand).ToUnit() : null; + d0 = u0.HasValue ? (u0.Value.ToDouble() + summand).ToUnit() : null; + d1 = u1.HasValue ? (u1.Value.ToDouble() + summand).ToUnit() : null; + d2 = u2.HasValue ? (u2.Value.ToDouble() + summand).ToUnit() : null; + d3 = u3.HasValue ? (u3.Value.ToDouble() + summand).ToUnit() : null; } // 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук) @@ -83,17 +74,52 @@ public static partial class CollectionsPlusExtensions T? unit = Unsafe.Add(ref srcRef, i); ref var dst = ref Unsafe.Add(ref dstRef, i); - dst = unit.HasValue ? (unit.Value.ToDouble() + summand).ToUnit() : null; + dst = unit.HasValue ? (unit.Value.ToDouble() + summand).ToUnit() : null; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Plus(this double summand, ReadOnlySpan units, Span destination) - where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); + internal static void PlusCore(this double summand, ReadOnlySpan units, int len, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable => units.PlusCore(summand, len, destination); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Plus(this double summand, ReadOnlySpan units, Span destination) - where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); + internal static void PlusCore(this double summand, ReadOnlySpan units, int len, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable => units.PlusCore(summand, len, destination); + + + + + // === ReadOnlySpan + public static void Plus(this ReadOnlySpan units, double multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this ReadOnlySpan units, double multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this double multiplicator, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(multiplicator, destination); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Plus(this double multiplicator, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(multiplicator, destination); // === Array === public static T[] Plus(this T[] units, double summand) @@ -114,20 +140,8 @@ public static partial class CollectionsPlusExtensions int len = units.Length; if (len == 0) return []; - // Выделяем чистую память (0 аллокаций логики, только сам массив) var result = new T?[len]; - - 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(); - } - } + Plus(units, summand, result); return result; } @@ -159,16 +173,7 @@ public static partial class CollectionsPlusExtensions if (count == 0) return []; var resultArray = new T?[count]; - ReadOnlySpan 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() + summand).ToUnit(); - } - } + Plus(CollectionsMarshal.AsSpan(units), summand, resultArray); return resultArray.WrapAsList(); } @@ -181,123 +186,90 @@ public static partial class CollectionsPlusExtensions where T : struct, IMensuraUnit, IEquatable => units.Plus(summand); // === ICollection === - public static ICollection Plus(this ICollection units, double summand) + public static void Plus(this ICollection units, double summand, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Plus(summand); - if (units is List list) return list.Plus(summand); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - units.CopyTo(sharedArray, 0); - Plus(new ReadOnlySpan(sharedArray, 0, count), summand, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { array.Plus(summand, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (item.ToDouble() + summand).ToUnit(); } - public static ICollection Plus(this ICollection units, double summand) + public static void Plus(this ICollection units, double summand, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return array.Plus(summand); - if (units is List list) return list.Plus(summand); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - var resultArray = new T?[count]; - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - try - { - units.CopyTo(sharedNullableArray, 0); - var srcSpan = new ReadOnlySpan(sharedNullableArray, 0, count); - srcSpan.Plus(summand, resultArray); - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { array.Plus(summand, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = item.HasValue + ? (item.Value.ToDouble() + summand).ToUnit() : null; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ICollection Plus(this double summand, ICollection units) - where T : struct, IMensuraUnit, IEquatable => units.Plus(summand); + public static void Plus(this double summand, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ICollection Plus(this double summand, ICollection units) - where T : struct, IMensuraUnit, IEquatable => units.Plus(summand); + public static void Plus(this double summand, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); // === IReadOnlyCollection === - public static IReadOnlyCollection Plus(this IReadOnlyCollection units, double summand) + public static void Plus(this IReadOnlyCollection units, double summand, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T[] array) return array.Plus(summand); - if (units is List list) return list.Plus(summand); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(count); - var finalResult = new T[count]; - try - { - int index = 0; - foreach (var item in units) sharedArray[index++] = item; - Plus(sharedArray, summand, finalResult.AsSpan()); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { array.Plus(summand, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (item.ToDouble() + summand).ToUnit(); } - public static IReadOnlyCollection Plus(this IReadOnlyCollection units, double summand) + public static void Plus(this IReadOnlyCollection units, double summand, Span destination) where T : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; + if (units is null) return; int count = units.Count; - if (count == 0) return []; - if (units is T?[] array) return array.Plus(summand); - if (units is List list) return list.Plus(summand); + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T?[] sharedNullableArray = ArrayPool.Shared.Rent(count); - var resultArray = new T?[count]; - try - { - 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() + summand).ToUnit(); - } - } - return resultArray; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { array.Plus(summand, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = item.HasValue + ? (item.Value.ToDouble() + summand).ToUnit() : null; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static IReadOnlyCollection Plus(this double summand, IReadOnlyCollection units) - where T : struct, IMensuraUnit, IEquatable => units.Plus(summand); + public static void Plus(this double summand, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static IReadOnlyCollection Plus(this double summand, IReadOnlyCollection units) - where T : struct, IMensuraUnit, IEquatable => units.Plus(summand); + public static void Plus(this double summand, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); // === IEnumerable + yeild === static IEnumerable PlusIterator(IEnumerable units, double summand) @@ -321,8 +293,18 @@ public static partial class CollectionsPlusExtensions if (units is null) return null!; if (units is T[] array) return array.Plus(summand); if (units is List list) return list.Plus(summand); - if (units is ICollection col) return col.Plus(summand); - if (units is IReadOnlyCollection roc) return roc.Plus(summand); + if (units is ICollection col) + { + var arr = new T[col.Count]; + col.Plus(summand, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T[roc.Count]; + roc.Plus(summand, arr); + return arr; + } return PlusIterator(units, summand); } public static IEnumerable Plus(this IEnumerable units, double summand) @@ -331,8 +313,18 @@ public static partial class CollectionsPlusExtensions if (units is null) return null!; if (units is T?[] array) return array.Plus(summand); if (units is List list) return list.Plus(summand); - if (units is ICollection col) return col.Plus(summand); - if (units is IReadOnlyCollection roc) return roc.Plus(summand); + if (units is ICollection col) + { + var arr = new T?[col.Count]; + col.Plus(summand, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new T?[roc.Count]; + roc.Plus(summand, arr); + return arr; + } return PlusNullableIterator(units, summand); } diff --git a/QWERTYkez.Mensura/Extensions/CollectionsPowExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsPowExtensions.cs index aa279fb..76be5aa 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsPowExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsPowExtensions.cs @@ -1,5 +1,4 @@ -using System.Buffers; -using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; namespace QWERTYkez.Mensura.Extensions; @@ -26,16 +25,11 @@ public static partial class CollectionsPowExtensions // === ЦЕЛАЯ СТЕПЕНЬ ========================================== - // === ReadOnlySpan === SIMD - internal static void Pow(this ReadOnlySpan units, int power, Span destination) + // === PowCore === SIMD + internal static void PowCore(this ReadOnlySpan units, int power, int len, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - int len = units.Length; - if (len == 0) return; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); Span dstDouble = MemoryMarshal.Cast(destination); @@ -111,15 +105,10 @@ public static partial class CollectionsPowExtensions Unsafe.Add(ref dstRef, i) = power < 0 ? 1.0 / result : result; } } - internal static void Pow(this ReadOnlySpan units, int power, Span destination) + internal static void PowCore(this ReadOnlySpan units, int power, int len, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - int len = units.Length; - if (len == 0) return; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - // Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора ref var srcRef = ref MemoryMarshal.GetReference(units); ref var dstRef = ref MemoryMarshal.GetReference(destination); @@ -158,6 +147,31 @@ public static partial class CollectionsPowExtensions } } + + // === ReadOnlySpan + internal static void Pow(this ReadOnlySpan units, int power, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable + { + int len = units.Length; + if (len == 0) return; + if (len > destination.Length) + throw new ArgumentException("Целевой буфер destination меньше исходного source."); + + units.PowCore(power, len, destination); + } + internal static void Pow(this ReadOnlySpan units, int power, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable + { + int len = units.Length; + if (len == 0) return; + if (len > destination.Length) + throw new ArgumentException("Целевой буфер destination меньше исходного source."); + + units.PowCore(power, len, destination); + } + // === Array === internal static R[] Pow(this T[] units, int power) where T : struct, IMensuraUnit, IEquatable @@ -221,7 +235,7 @@ public static partial class CollectionsPowExtensions if (destination.Length < count) 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 list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; } int i = 0; @@ -238,7 +252,7 @@ public static partial class CollectionsPowExtensions if (destination.Length < count) 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 list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; } int i = 0; @@ -258,7 +272,7 @@ public static partial class CollectionsPowExtensions if (destination.Length < count) 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 list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; } int i = 0; @@ -275,7 +289,7 @@ public static partial class CollectionsPowExtensions if (destination.Length < count) 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 list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; } int i = 0; @@ -309,8 +323,18 @@ public static partial class CollectionsPowExtensions if (units is null) return null!; if (units is T[] array) return array.Pow(power); if (units is List list) return list.Pow(power); - if (units is ICollection col) return col.Pow(power); - if (units is IReadOnlyCollection roc) return roc.Pow(power); + if (units is ICollection col) + { + var arr = new R[col.Count]; + col.Pow(power, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new R[roc.Count]; + roc.Pow(power, arr); + return arr; + } else return PowIterator(units, power); } internal static IEnumerable Pow(this IEnumerable units, int power) @@ -320,24 +344,29 @@ public static partial class CollectionsPowExtensions if (units is null) return null!; if (units is T?[] array) return array.Pow(power); if (units is List list) return list.Pow(power); - if (units is ICollection col) return col.Pow(power); - if (units is IReadOnlyCollection roc) return roc.Pow(power); + if (units is ICollection col) + { + var arr = new R?[col.Count]; + col.Pow(power, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new R?[roc.Count]; + roc.Pow(power, arr); + return arr; + } else return PowNullableIterator(units, power); } // === ДРОБНАЯ СТЕПЕНЬ ========================================== - // === ReadOnlySpan === - internal static void Pow(this ReadOnlySpan units, double power, Span destination) + // === PowCore === SIMD + internal static void PowCore(this ReadOnlySpan units, double power, int len, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - int len = units.Length; - if (len == 0) return; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); Span dstDouble = MemoryMarshal.Cast(destination); @@ -413,15 +442,10 @@ public static partial class CollectionsPowExtensions Unsafe.Add(ref dstRef, i) = Math.Pow(Unsafe.Add(ref srcRef, i), power); } } - internal static void Pow(this ReadOnlySpan units, double power, Span destination) + internal static void PowCore(this ReadOnlySpan units, double power, int len, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - int len = units.Length; - if (len == 0) return; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - for (int i = 0; i < len; i++) { T? item = units[i]; @@ -434,6 +458,32 @@ public static partial class CollectionsPowExtensions } } + + + // === ReadOnlySpan === + internal static void Pow(this ReadOnlySpan units, double power, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable + { + int len = units.Length; + if (len == 0) return; + if (len > destination.Length) + throw new ArgumentException("Целевой буфер destination меньше исходного source."); + + units.PowCore(power, len, destination); + } + internal static void Pow(this ReadOnlySpan units, double power, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable + { + int len = units.Length; + if (len == 0) return; + if (len > destination.Length) + throw new ArgumentException("Целевой буфер destination меньше исходного source."); + + units.PowCore(power, len, destination); + } + // === Array === internal static R[] Pow(this T[] units, double power) where T : struct, IMensuraUnit, IEquatable @@ -443,35 +493,20 @@ public static partial class CollectionsPowExtensions int len = units.Length; if (len == 0) return []; - var finalResult = new R[len]; - if (power != 0.5) - { - for (int i = 0; i < len; i++) - { - ref var dst = ref finalResult[i]; - dst = Math.Pow(units[i].ToDouble(), power).ToUnit(); - } - } - else MemoryMarshal.Cast(units).Sqrt(finalResult); - return finalResult; + var result = new R[len]; + units.Pow(power, result); + return result; } internal static R?[] Pow(this T?[] units, double power) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return null!; - if (units.Length == 0) return []; + int len = units.Length; + if (len == 0) return []; - var result = (R?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) - { - item = Math.Pow(item.Value.ToDouble(), power).ToUnit(); - } - } + var result = new R?[len]; + units.Pow(power, result); return result; } @@ -484,23 +519,9 @@ public static partial class CollectionsPowExtensions int len = units.Count; if (len == 0) return []; - var resultArray = new R[len]; - var srcSpan = CollectionsMarshal.AsSpan(units); - if (power == 0.5) - { - ReadOnlySpan srcAsR = MemoryMarshal.Cast(srcSpan); - srcAsR.Sqrt(resultArray); - } - else - { - Span dstSpan = resultArray.AsSpan(); - for (int i = 0; i < len; i++) - { - ref var dst = ref dstSpan[i]; - dst = Math.Pow(srcSpan[i].ToDouble(), power).ToUnit(); - } - } - return resultArray.WrapAsList(); + var result = new R[len]; + CollectionsMarshal.AsSpan(units).Pow(power, result); + return result.WrapAsList(); } internal static List Pow(this List units, double power) where T : struct, IMensuraUnit, IEquatable @@ -510,155 +531,83 @@ public static partial class CollectionsPowExtensions int len = units.Count; if (len == 0) return []; - var resultArray = new R?[len]; - var srcSpan = CollectionsMarshal.AsSpan(units); - for (int i = 0; i < len; i++) - { - T? item = srcSpan[i]; - if (item.HasValue) - { - ref var dst = ref resultArray[i]; - dst = Math.Pow(item.Value.ToDouble(), power).ToUnit(); - } - } - return resultArray.WrapAsList(); + var result = new R?[len]; + CollectionsMarshal.AsSpan(units).Pow(power, result); + return result.WrapAsList(); } // === ICollection === - internal static ICollection Pow(this ICollection units, double power) + internal static void Pow(this ICollection units, double power, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - if (units is T[] array) return array.Pow(power); - if (units is List list) return list.Pow(power); + if (units is null) return; + int count = units.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(len); - var finalResult = new R[len]; - try - { - units.CopyTo(sharedArray, 0); - if (power == 0.5) - { - MemoryMarshal.Cast(sharedArray).Sqrt(finalResult); - } - else - { - for (int i = 0; i < len; i++) - finalResult[i] = Math.Pow(sharedArray[i].ToDouble(), power).ToUnit(); - } - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { array.Pow(power, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; } + + int i = 0; + foreach (T item in units) + destination[i++] = Math.Pow(item.ToDouble(), power).ToUnit(); } - internal static ICollection Pow(this ICollection units, double power) + internal static void Pow(this ICollection units, double power, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - if (units is T?[] array) return array.Pow(power); - if (units is List list) return list.Pow(power); + if (units is null) return; + int count = units.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T?[] sharedNullableArray = ArrayPool.Shared.Rent(len); - var finalResult = new R?[len]; - try - { - units.CopyTo(sharedNullableArray, 0); - for (int i = 0; i < len; i++) - { - T? item = sharedNullableArray[i]; - finalResult[i] = item.HasValue ? Math.Pow(item.Value.ToDouble(), power).ToUnit() : default; - } - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { array.Pow(power, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; } + + int i = 0; + foreach (T? item in units) + destination[i++] = item.HasValue + ? Math.Pow(item.Value.ToDouble(), power).ToUnit() : null; } // === IReadOnlyCollection === - internal static IReadOnlyCollection Pow(this IReadOnlyCollection units, double power) + internal static void Pow(this IReadOnlyCollection units, double power, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - if (units is T[] array) return array.Pow(power); - if (units is List list) return list.Pow(power); + if (units is null) return; + int count = units.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - var finalResult = new R[len]; - var sharedArray = ArrayPool.Shared.Rent(len); - try - { - if (units is ICollection collection) - { - collection.CopyTo(sharedArray, 0); - } - else - { - int idx = 0; - foreach (var item in units) sharedArray[idx++] = item; - } + if (units is T[] array) { array.Pow(power, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; } - if (power != 0.5) - { - for (int i = 0; i < len; i++) - finalResult[i] = Math.Pow(sharedArray[i].ToDouble(), power).ToUnit(); - } - else MemoryMarshal.Cast(sharedArray).Sqrt(finalResult); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + int i = 0; + foreach (T item in units) + destination[i++] = Math.Pow(item.ToDouble(), power).ToUnit(); } - internal static IReadOnlyCollection Pow(this IReadOnlyCollection units, double power) + internal static void Pow(this IReadOnlyCollection units, double power, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - if (units is T?[] array) return array.Pow(power); - if (units is List list) return list.Pow(power); + if (units is null) return; + int count = units.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - var finalResult = new R?[len]; - T?[] sharedNullableArray = ArrayPool.Shared.Rent(len); + if (units is T?[] array) { array.Pow(power, destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; } - try - { - if (units is ICollection collection) - { - 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() : default; - } - - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + int i = 0; + foreach (T? item in units) + destination[i++] = item.HasValue + ? Math.Pow(item.Value.ToDouble(), power).ToUnit() : null; } // === IEnumerable + yield === @@ -686,8 +635,18 @@ public static partial class CollectionsPowExtensions if (units is null) return null!; if (units is T[] array) return array.Pow(power); if (units is List list) return list.Pow(power); - if (units is ICollection col) return col.Pow(power); - if (units is IReadOnlyCollection roc) return roc.Pow(power); + if (units is ICollection col) + { + var arr = new R[col.Count]; + col.Pow(power, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new R[roc.Count]; + roc.Pow(power, arr); + return arr; + } else return PowIterator(units, power); } internal static IEnumerable Pow(this IEnumerable units, double power) @@ -697,8 +656,18 @@ public static partial class CollectionsPowExtensions if (units is null) return null!; if (units is T?[] array) return array.Pow(power); if (units is List list) return list.Pow(power); - if (units is ICollection col) return col.Pow(power); - if (units is IReadOnlyCollection roc) return roc.Pow(power); + if (units is ICollection col) + { + var arr = new R?[col.Count]; + col.Pow(power, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new R?[roc.Count]; + roc.Pow(power, arr); + return arr; + } else return PowNullableIterator(units, power); } } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Extensions/CollectionsSqrtExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsSqrtExtensions.cs index 8911616..8988231 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsSqrtExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsSqrtExtensions.cs @@ -1,21 +1,14 @@ -using System.Buffers; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics.X86; namespace QWERTYkez.Mensura.Extensions; public static partial class CollectionsSqrtExtensions { - // === ReadOnlySpan === SIMD - internal static void Sqrt(this ReadOnlySpan units, Span destination) + // === SqrtCore === SIMD + internal static unsafe void SqrtCore(this ReadOnlySpan units, int len, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); Span dstDouble = MemoryMarshal.Cast(destination); @@ -27,21 +20,21 @@ public static partial class CollectionsSqrtExtensions // 1. ПУТЬ AVX (x64 Процессоры Intel/AMD) — обрабатываем по 4 элемента double if (Avx.IsSupported && len >= 4) { - int simdEnd = len & ~3; // Вычисляем границу по маске (быстрее, чем len - len % 4) - + int simdEnd = len & ~3; for (; i < simdEnd; i += 4) { ref double currentSrc = ref Unsafe.Add(ref srcRef, i); ref double currentDst = ref Unsafe.Add(ref dstRef, i); - // Загружаем 4 элемента double в AVX регистр за 1 такт - var v = Unsafe.As>(ref currentSrc); + // Получаем указатели через Unsafe.AsPointer + 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); - - // Выгружаем результат обратно в память назначения за 1 такт - Unsafe.As>(ref currentDst) = sqrtV; + // Выровненное сохранение + Avx.Store(pDst, sqrtV); } } // 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)); } } - public static void Sqrt(this ReadOnlySpan units, Span destination) + public static void SqrtCore(this ReadOnlySpan units, int len, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - if (units.IsEmpty) return; - int len = units.Length; - if (len > destination.Length) - throw new ArgumentException("Целевой буфер destination меньше исходного source."); - // Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора ref var srcRef = ref MemoryMarshal.GetReference(units); ref var dstRef = ref MemoryMarshal.GetReference(destination); @@ -115,6 +103,33 @@ public static partial class CollectionsSqrtExtensions } } + + + + // === ReadOnlySpan === + internal static void Sqrt(this ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable + { + 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(this ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable + { + if (units.IsEmpty) return; + int len = units.Length; + if (len > destination.Length) + throw new ArgumentException("Целевой буфер destination меньше исходного source."); + + units.SqrtCore(len, destination); + } + // === Array === public static R[] Sqrt(this T[] units) where T : struct, IMensuraUnit, IEquatable @@ -161,69 +176,82 @@ public static partial class CollectionsSqrtExtensions if (len == 0) return []; var resultArray = new R?[len]; - var srcSpan = CollectionsMarshal.AsSpan(units); - 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(); - } - } + Sqrt(CollectionsMarshal.AsSpan(units), resultArray); return resultArray.WrapAsList(); } // === ICollection === - public static ICollection Sqrt(this ICollection units) + public static void Sqrt(this ICollection units, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - if (units is T[] array) return array.Sqrt(); - if (units is List list) return list.Sqrt(); + if (units is null) return; + int count = units.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T[] sharedArray = ArrayPool.Shared.Rent(len); - var finalResult = new R[len]; - try - { - units.CopyTo(sharedArray, 0); - MemoryMarshal.Cast(sharedArray).Sqrt(finalResult); - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedArray); - } + if (units is T[] array) { array.Sqrt(destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; } + + int i = 0; + foreach (T item in units) + destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit(); } - public static ICollection Sqrt(this ICollection units) + public static void Sqrt(this ICollection units, Span destination) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - if (units is T?[] array) return array.Sqrt(); - if (units is List list) return list.Sqrt(); + if (units is null) return; + int count = units.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); - T?[] sharedNullableArray = ArrayPool.Shared.Rent(len); - var finalResult = new R?[len]; - try - { - units.CopyTo(sharedNullableArray, 0); - for (int i = 0; i < len; i++) - { - T? item = sharedNullableArray[i]; - finalResult[i] = item.HasValue ? Math.Sqrt(item.Value.ToDouble()).ToUnit() : default; - } - return finalResult; - } - finally - { - ArrayPool.Shared.Return(sharedNullableArray); - } + if (units is T?[] array) { array.Sqrt(destination); return; } + if (units is List 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() : null; + } + + // === IReadOnlyCollection === + public static void Sqrt(this IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable + { + if (units is null) return; + int count = units.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (units is T[] array) { array.Sqrt(destination); return; } + if (units is List list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; } + + int i = 0; + foreach (T item in units) + destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit(); + } + public static void Sqrt(this IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable + { + if (units is null) return; + int count = units.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (units is T?[] array) { array.Sqrt(destination); return; } + if (units is List 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() : null; } // === IEnumerable + yield === @@ -244,26 +272,46 @@ public static partial class CollectionsSqrtExtensions } // === IEnumerable === - internal static IEnumerable Sqrt(this IEnumerable units, double Sqrter) + internal static IEnumerable Sqrt(this IEnumerable units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return null!; - if (units is T[] array) return array.Sqrt(Sqrter); - if (units is List list) return list.Sqrt(Sqrter); - if (units is ICollection col) return col.Sqrt(Sqrter); - if (units is IReadOnlyCollection roc) return roc.Sqrt(Sqrter); + if (units is T[] array) return array.Sqrt(); + if (units is List list) return list.Sqrt(); + if (units is ICollection col) + { + var arr = new R[col.Count]; + col.Sqrt(arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new R[roc.Count]; + roc.Sqrt(arr); + return arr; + } else return SqrtIterator(units); } - internal static IEnumerable Sqrt(this IEnumerable units, double Sqrter) + internal static IEnumerable Sqrt(this IEnumerable units) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { if (units is null) return null!; - if (units is T?[] array) return array.Sqrt(Sqrter); - if (units is List list) return list.Sqrt(Sqrter); - if (units is ICollection col) return col.Sqrt(Sqrter); - if (units is IReadOnlyCollection roc) return roc.Sqrt(Sqrter); + if (units is T?[] array) return array.Sqrt(); + if (units is List list) return list.Sqrt(); + if (units is ICollection col) + { + var arr = new R?[col.Count]; + col.Sqrt(arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new R?[roc.Count]; + roc.Sqrt(arr); + return arr; + } else return SqrtNullableIterator(units); } } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Extensions/ToDouble.cs b/QWERTYkez.Mensura/Extensions/ToDouble.cs index eeb4007..0cf525e 100644 --- a/QWERTYkez.Mensura/Extensions/ToDouble.cs +++ b/QWERTYkez.Mensura/Extensions/ToDouble.cs @@ -1,6 +1,4 @@ -using System.Globalization; - -namespace QWERTYkez.Mensura.Extensions; +namespace QWERTYkez.Mensura.Extensions; internal static partial class ToDoubleExtensions { diff --git a/QWERTYkez.Mensura/Operators.cs b/QWERTYkez.Mensura/Operators.cs index 8688d3e..2656402 100644 --- a/QWERTYkez.Mensura/Operators.cs +++ b/QWERTYkez.Mensura/Operators.cs @@ -1,231 +1,231 @@ -namespace QWERTYkez.Mensura.Units; +//namespace QWERTYkez.Mensura.Units; -internal static class OperationsExtension -{ - internal static TResult MultiplyProtected(this T1 t1, T2 t2) - where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit - => new() { Value = t1.Value * t2.Value }; - - internal static TResult MultiplyProtected(this T1 t1, T2 t2, double multiplicator) - where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit - => new() { Value = t1.Value * t2.Value * multiplicator }; - - internal static TResult DivideProtected(this T1 t1, T2 t2) - where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit - => new() { Value = t1.Value / t2.Value }; - - internal static TResult DivideProtected(this T1 t1, T2 t2, double multiplicator) - where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit - => new() { Value = t1.Value * multiplicator / t2.Value }; -} - -internal static class Coefficients -{ - internal static double MultiplyCoefficient(T1 a, T2 b, TResult r) - where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit - => r.Value / (a.Value * b.Value); - - internal static double DivideCoefficient(T1 a, T2 b, TResult r) - where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit - where TResult : struct, IMensuraUnit, IEquatable, 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(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(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(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(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(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(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(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(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(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(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(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(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(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(right); - [CollectionsOperatorsGenerator] public static Length operator /(Volume left, Area right) => left.DivideProtected(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(right, Coeff1); - static readonly double Coeff1 = Coefficients.MultiplyCoefficient(MassPerSquare.KiloGramPerMeterSquared, Boost.MeterPerSecondSquared, Pressure.Pascal); -} - -//[CollectionsOperatorsGenerator] public readonly partial record struct PogonForce : Pogon +//internal static class OperationsExtension //{ +// internal static TResult MultiplyProtected(this T1 t1, T2 t2) +// where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit +// => new() { Value = t1.Value * t2.Value }; +// internal static TResult MultiplyProtected(this T1 t1, T2 t2, double multiplicator) +// where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit +// => new() { Value = t1.Value * t2.Value * multiplicator }; + +// internal static TResult DivideProtected(this T1 t1, T2 t2) +// where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit +// => new() { Value = t1.Value / t2.Value }; + +// internal static TResult DivideProtected(this T1 t1, T2 t2, double multiplicator) +// where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit +// => new() { Value = t1.Value * multiplicator / t2.Value }; +//} + +//internal static class Coefficients +//{ +// internal static double MultiplyCoefficient(T1 a, T2 b, TResult r) +// where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where TResult : struct, IMensuraUnit, IEquatable, IMensuraUnit +// => r.Value / (a.Value * b.Value); + +// internal static double DivideCoefficient(T1 a, T2 b, TResult r) +// where T1 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where T2 : struct, IMensuraUnit, IEquatable, IMensuraUnit +// where TResult : struct, IMensuraUnit, IEquatable, 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(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(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(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(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(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 +//[CollectionsOperatorsGenerator] public readonly partial record struct Pressure // Pascals //{ -// [CollectionsOperatorsGenerator] public static Boost operator /(PogonForce left, PogonMass right) => left.DivideProtected(right, Coeff1); +// [CollectionsOperatorsGenerator] public static Length operator /(Pressure left, UdelForce right) => left.DivideProtected(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(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(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(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 +//[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(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(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(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(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(right); +// [CollectionsOperatorsGenerator] public static Length operator /(Volume left, Area right) => left.DivideProtected(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(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(right, Coeff2); +// static readonly double Coeff2 = Coefficients.DivideCoefficient(Force.Newton, Area.MeterSquared, Pressure.Pascal); //} -//[CollectionsOperatorsGenerator] public readonly partial record struct Density : Udel +//[CollectionsOperatorsGenerator] public readonly partial record struct Torque // NewtonMeters +//{ +// [CollectionsOperatorsGenerator] public static Length operator /(Torque left, Force right) => left.DivideProtected(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(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(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(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(right, Coeff5); +// static readonly double Coeff5 = Coefficients.DivideCoefficient(Torque.Newton_Meter, Pressure.Pascal, Volume.MeterCubic); +//} + +//[CollectionsOperatorsGenerator] public readonly partial record struct Frequency // Hertz //{ +//} -//} \ No newline at end of file +//[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(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(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(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(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(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(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(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(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(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(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(right, Coeff1); +// static readonly double Coeff1 = Coefficients.MultiplyCoefficient(MassPerSquare.KiloGramPerMeterSquared, Boost.MeterPerSecondSquared, Pressure.Pascal); +//} + +////[CollectionsOperatorsGenerator] public readonly partial record struct PogonForce : Pogon +////{ + + +////} + +////[CollectionsOperatorsGenerator] public readonly partial record struct PogonMass : Pogon +////{ +//// [CollectionsOperatorsGenerator] public static Boost operator /(PogonForce left, PogonMass right) => left.DivideProtected(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 +////{ + + +////} + +////[CollectionsOperatorsGenerator] public readonly partial record struct Density : Udel +////{ + + +////} \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/Pogon/.Pogon.cs b/QWERTYkez.Mensura/Units/Pogon/.Pogon.cs index 51f9891..62f5124 100644 --- a/QWERTYkez.Mensura/Units/Pogon/.Pogon.cs +++ b/QWERTYkez.Mensura/Units/Pogon/.Pogon.cs @@ -1,13 +1,13 @@ -namespace MetricSystem; +//namespace MetricSystem; -/// -/// Base value is PerMilliMeter -/// -public abstract class Pogon -{ +///// +///// Base value is PerMilliMeter +///// +//public abstract class Pogon +//{ - internal T PerValue { get; init; } +// internal T PerValue { get; init; } @@ -15,135 +15,135 @@ public abstract class Pogon - [NotMapped, JsonIgnore] internal T PerValue - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value - }; - } - set - { - Value = value.Value; - } - } - [NotMapped, JsonIgnore] public T _PerMilliMeter - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value - }; - } - set - { - Value = value.Value; - } - } +// [NotMapped, JsonIgnore] internal T PerValue +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value +// }; +// } +// set +// { +// Value = value.Value; +// } +// } +// [NotMapped, JsonIgnore] public T _PerMilliMeter +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value +// }; +// } +// set +// { +// Value = value.Value; +// } +// } - [NotMapped, JsonIgnore] public T PerMilliMeter - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value - }; - } - set - { - Value = value.Value; - } - } - [NotMapped, JsonIgnore] public T PerCentiMeter - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value * LengthConv.CentiMeters.Multiplicator, - BaseContainerMultiplicator = LengthConv.CentiMeters.Multiplicator, - }; - } - set - { - Value = value.Value / LengthConv.CentiMeters.Multiplicator; - } - } - [NotMapped, JsonIgnore] public T PerDeciMeter - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value * LengthConv.DeciMeters.Multiplicator, - BaseContainerMultiplicator = LengthConv.DeciMeters.Multiplicator, - }; - } - set - { - Value = value.Value / LengthConv.DeciMeters.Multiplicator; - } - } - [NotMapped, JsonIgnore] public T PerMeter - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value * LengthConv.Meters.Multiplicator, - BaseContainerMultiplicator = LengthConv.Meters.Multiplicator, - }; - } - set - { - Value = value.Value / LengthConv.Meters.Multiplicator; - } - } - [NotMapped, JsonIgnore] public T PerKiloMeter - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value * LengthConv.KiloMeters.Multiplicator, - BaseContainerMultiplicator = LengthConv.KiloMeters.Multiplicator, - }; - } - set - { - Value = value.Value / LengthConv.KiloMeters.Multiplicator; - } - } +// [NotMapped, JsonIgnore] public T PerMilliMeter +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value +// }; +// } +// set +// { +// Value = value.Value; +// } +// } +// [NotMapped, JsonIgnore] public T PerCentiMeter +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value * LengthConv.CentiMeters.Multiplicator, +// BaseContainerMultiplicator = LengthConv.CentiMeters.Multiplicator, +// }; +// } +// set +// { +// Value = value.Value / LengthConv.CentiMeters.Multiplicator; +// } +// } +// [NotMapped, JsonIgnore] public T PerDeciMeter +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value * LengthConv.DeciMeters.Multiplicator, +// BaseContainerMultiplicator = LengthConv.DeciMeters.Multiplicator, +// }; +// } +// set +// { +// Value = value.Value / LengthConv.DeciMeters.Multiplicator; +// } +// } +// [NotMapped, JsonIgnore] public T PerMeter +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value * LengthConv.Meters.Multiplicator, +// BaseContainerMultiplicator = LengthConv.Meters.Multiplicator, +// }; +// } +// set +// { +// Value = value.Value / LengthConv.Meters.Multiplicator; +// } +// } +// [NotMapped, JsonIgnore] public T PerKiloMeter +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value * LengthConv.KiloMeters.Multiplicator, +// BaseContainerMultiplicator = LengthConv.KiloMeters.Multiplicator, +// }; +// } +// set +// { +// Value = value.Value / LengthConv.KiloMeters.Multiplicator; +// } +// } - public static T operator *(Pogon left, Length right) => ((U)left).Protect()._PerMilliMeter * right.Protect()._MilliMeters; - public static MetricCollection operator *(Pogon left, MetricCollection right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); - public static MetricArray operator *(Pogon left, MetricArray right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); - public static MetricList operator *(Pogon left, MetricList right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); - public static MetricObservableCollection operator *(Pogon left, MetricObservableCollection right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); +// public static T operator *(Pogon left, Length right) => ((U)left).Protect()._PerMilliMeter * right.Protect()._MilliMeters; +// public static MetricCollection operator *(Pogon left, MetricCollection right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); +// public static MetricArray operator *(Pogon left, MetricArray right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); +// public static MetricList operator *(Pogon left, MetricList right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); +// public static MetricObservableCollection operator *(Pogon left, MetricObservableCollection right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); - public static T operator *(Length left, Pogon right) => ((U)right).Protect()._PerMilliMeter * left.Protect()._MilliMeters; - public static MetricCollection operator *(MetricCollection left, Pogon right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); - public static MetricArray operator *(MetricArray left, Pogon right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); - public static MetricList operator *(MetricList left, Pogon right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); - public static MetricObservableCollection operator *(MetricObservableCollection left, Pogon right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); +// public static T operator *(Length left, Pogon right) => ((U)right).Protect()._PerMilliMeter * left.Protect()._MilliMeters; +// public static MetricCollection operator *(MetricCollection left, Pogon right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); +// public static MetricArray operator *(MetricArray left, Pogon right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); +// public static MetricList operator *(MetricList left, Pogon right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); +// public static MetricObservableCollection operator *(MetricObservableCollection left, Pogon right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); - public static Length operator /(T left, Pogon right) => new() { _MilliMeters = left.Protect() / ((U)right).Protect()._PerMilliMeter }; - public static MetricCollection operator *(MetricCollection left, Pogon right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); - public static MetricArray operator *(MetricArray left, Pogon right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); - public static MetricList operator *(MetricList left, Pogon right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); - public static MetricObservableCollection operator *(MetricObservableCollection left, Pogon right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); -} \ No newline at end of file +// public static Length operator /(T left, Pogon right) => new() { _MilliMeters = left.Protect() / ((U)right).Protect()._PerMilliMeter }; +// public static MetricCollection operator *(MetricCollection left, Pogon right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); +// public static MetricArray operator *(MetricArray left, Pogon right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); +// public static MetricList operator *(MetricList left, Pogon right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); +// public static MetricObservableCollection operator *(MetricObservableCollection left, Pogon right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); +//} \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/Pogon/PogonForce.cs b/QWERTYkez.Mensura/Units/Pogon/PogonForce.cs index a8e767b..7302a22 100644 --- a/QWERTYkez.Mensura/Units/Pogon/PogonForce.cs +++ b/QWERTYkez.Mensura/Units/Pogon/PogonForce.cs @@ -1,14 +1,14 @@ -namespace MetricSystem; +//namespace MetricSystem; -[DebuggerDisplay("N/m = {PerMeter._Newtons.ToString(\"0.###\")}, kgf/m = {PerMeter.KiloGramXXXXXXXXs.ToString(\"0.###\")}")] -public readonly partial record struct PogonXXXXXXXX -{ +//[DebuggerDisplay("N/m = {PerMeter._Newtons.ToString(\"0.###\")}, kgf/m = {PerMeter.KiloGramXXXXXXXXs.ToString(\"0.###\")}")] +//public readonly partial record struct PogonXXXXXXXX +//{ -} +//} -public partial class Length : Metric -{ - [CollectionsOperatorsGenerator] public static PogonXXXXXXXX operator /(XXXXXXXX left, Length right) => left.DivideProtected(right, PogonXXXXXXXXCoeff); - static readonly double PogonXXXXXXXXCoeff = Coefficients.DivideCoefficient(a => a.Value = 1, b => b._MilliMeters = 1, r => r._PerMilliMeter.Value = 1); -} \ No newline at end of file +//public partial class Length : Metric +//{ +// [CollectionsOperatorsGenerator] public static PogonXXXXXXXX operator /(XXXXXXXX left, Length right) => left.DivideProtected(right, PogonXXXXXXXXCoeff); +// static readonly double PogonXXXXXXXXCoeff = Coefficients.DivideCoefficient(a => a.Value = 1, b => b._MilliMeters = 1, r => r._PerMilliMeter.Value = 1); +//} \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/Pogon/PogonMass.cs b/QWERTYkez.Mensura/Units/Pogon/PogonMass.cs index a78744e..3775e6d 100644 --- a/QWERTYkez.Mensura/Units/Pogon/PogonMass.cs +++ b/QWERTYkez.Mensura/Units/Pogon/PogonMass.cs @@ -1,14 +1,14 @@ -namespace MetricSystem; +//namespace MetricSystem; -[Owned, JsonConverter(typeof(MetricFormatter)), DebuggerDisplay("gr/m = {PerMeter._Grams.ToString(\"0.###\")}, kg/m = {PerMeter.KiloGrams.ToString(\"0.###\")}")] -public partial class PogonMass : Pogon -{ - [CollectionsOperatorsGenerator] public static Density operator /(PogonMass left, Area right) => left.DivideProtected(right, UdelMassCoeff); - static readonly double UdelMassCoeff = Coefficients.DivideCoefficient(a => a._PerMilliMeter.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeterCubic.Value = 1); -} +//[Owned, JsonConverter(typeof(MetricFormatter)), DebuggerDisplay("gr/m = {PerMeter._Grams.ToString(\"0.###\")}, kg/m = {PerMeter.KiloGrams.ToString(\"0.###\")}")] +//public partial class PogonMass : Pogon +//{ +// [CollectionsOperatorsGenerator] public static Density operator /(PogonMass left, Area right) => left.DivideProtected(right, UdelMassCoeff); +// static readonly double UdelMassCoeff = Coefficients.DivideCoefficient(a => a._PerMilliMeter.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeterCubic.Value = 1); +//} -public partial class Length : Metric -{ - [CollectionsOperatorsGenerator] public static PogonMass operator /(Mass left, Length right) => left.DivideProtected(right, PogonMassCoeff); - static readonly double PogonMassCoeff = Coefficients.DivideCoefficient(a => a.Value = 1, b => b._MilliMeters = 1, r => r._PerMilliMeter.Value = 1); -} \ No newline at end of file +//public partial class Length : Metric +//{ +// [CollectionsOperatorsGenerator] public static PogonMass operator /(Mass left, Length right) => left.DivideProtected(right, PogonMassCoeff); +// static readonly double PogonMassCoeff = Coefficients.DivideCoefficient(a => a.Value = 1, b => b._MilliMeters = 1, r => r._PerMilliMeter.Value = 1); +//} \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/Pogon/PogonXXXXXXXX.Gen.cs b/QWERTYkez.Mensura/Units/Pogon/PogonXXXXXXXX.Gen.cs index 6cd6c11..17d640f 100644 --- a/QWERTYkez.Mensura/Units/Pogon/PogonXXXXXXXX.Gen.cs +++ b/QWERTYkez.Mensura/Units/Pogon/PogonXXXXXXXX.Gen.cs @@ -1,7 +1,7 @@ #if DEBUG -global using PogonMass = QWERTYkez.Mensura.Units.Pogon.PogonMass; global using PogonMassExtensions = QWERTYkez.Mensura.Units.Pogon.PogonMassExtensions; global using PogonMassConverter = QWERTYkez.Mensura.Units.Pogon.PogonMassConverter; +global using PogonMass = QWERTYkez.Mensura.Units.Pogon.PogonMass; using System.Globalization; using System.Runtime.Serialization; @@ -10,6 +10,146 @@ namespace QWERTYkez.Mensura.Units { 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 === + public static List operator *(List 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 operator *(List 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 operator *( + Length multiplicator, List units) => units * multiplicator; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List operator *( + Length multiplicator, List units) => units * multiplicator; + + // === IEnumerable === + public static IEnumerable Multiply(IEnumerable units, Length multiplicator) + { + if (units is null) return null!; + if (units is PogonMass[] array) return array.Multiply(multiplicator); + if (units is List list) return list.Multiply(multiplicator); + if (units is ICollection col) + { + var arr = new Mass[col.Count]; + col.Multiply(multiplicator, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new Mass[roc.Count]; + roc.Multiply(multiplicator, arr); + return arr; + } + return MultiplyIterator(units, multiplicator); + } + public static IEnumerable Multiply(IEnumerable units, Length multiplicator) + { + if (units is null) return null!; + if (units is PogonMass?[] array) return array.Multiply(multiplicator); + if (units is List list) return list.Multiply(multiplicator); + if (units is ICollection col) + { + var arr = new Mass?[col.Count]; + col.Multiply(multiplicator, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new Mass?[roc.Count]; + roc.Multiply(multiplicator, arr); + return arr; + } + return MultiplyNullableIterator(units, multiplicator); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Multiply( + Length multiplicator, IEnumerable units) => Multiply(units, multiplicator); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Multiply( + Length multiplicator, IEnumerable units) => Multiply(units, multiplicator); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + // ========================================== // === MULTIPLY === // ========================================== @@ -83,7 +223,7 @@ namespace QWERTYkez.Mensura.Units result[i] = val * right[i]; return result; } - public static Span operator *(this ReadOnlySpan left, Length right) + public static Span operator *(ReadOnlySpan left, Length right) { int len = left.Length; if (len == 0) return []; @@ -93,7 +233,7 @@ namespace QWERTYkez.Mensura.Units result[i] = right * left[i]; return result; } - public static Span operator *(this ReadOnlySpan left, Length? right) + public static Span operator *(ReadOnlySpan left, Length? right) { int len = left.Length; if (len == 0) return []; @@ -277,7 +417,7 @@ namespace QWERTYkez.Mensura.Units.Pogon result[i] = val * right[i]; return result; } - public static Span operator *(this ReadOnlySpan left, PogonMass right) + public static Span operator *(ReadOnlySpan left, PogonMass right) { int len = left.Length; if (len == 0) return []; @@ -287,7 +427,7 @@ namespace QWERTYkez.Mensura.Units.Pogon result[i] = right * left[i]; return result; } - public static Span operator *(this ReadOnlySpan left, PogonMass? right) + public static Span operator *(ReadOnlySpan left, PogonMass? right) { int len = left.Length; if (len == 0) return []; @@ -364,70 +504,261 @@ namespace QWERTYkez.Mensura.Units.Pogon public static PogonMass MetricAverage(this IEnumerable units) => new(units?.Average(m => m.ToDouble()) ?? double.NaN); public static PogonMass MetricMax(this IEnumerable units) => new(units?.Max(m => m.ToDouble()) ?? double.MinValue); public static PogonMass MetricMin(this IEnumerable units) => new(units?.Min(m => m.ToDouble()) ?? double.MaxValue); + + + + + + + + + + + + + + + + + + + + + + // === ReadOnlySpan + public static void Multiply(this ReadOnlySpan units, Length multiplicator, Span destination) + => units.MultiplyCore(multiplicator._Value, destination); + public static void Multiply(this ReadOnlySpan units, Length multiplicator, Span destination) + => units.MultiplyCore(multiplicator._Value, destination); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Multiply(this Length multiplicator, + ReadOnlySpan units, Span destination) => units.MultiplyCore(multiplicator._Value, destination); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Multiply(this Length multiplicator, + ReadOnlySpan units, Span 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 === + public static List Multiply(this List 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 Multiply(this List 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 Multiply( + this Length multiplicator, List units) => units.Multiply(multiplicator); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static List Multiply( + this Length multiplicator, List units) => units.Multiply(multiplicator); + + // === ICollection === + public static void Multiply(this ICollection units, Length multiplicator, Span 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 list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (item.ToDouble() * multiplicator._Value).ToUnit(); + } + public static void Multiply(this ICollection units, Length multiplicator, Span 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 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() : null; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Multiply(this Length multiplicator, + ICollection units, Span destination) => units.Multiply(multiplicator, destination); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Multiply(this Length multiplicator, + ICollection units, Span destination) => units.Multiply(multiplicator, destination); + + // === IReadOnlyCollection === + public static void Multiply(this IReadOnlyCollection units, Length multiplicator, Span 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 list) { CollectionsMarshal.AsSpan(list).Multiply(multiplicator, destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (item.ToDouble() * multiplicator._Value).ToUnit(); + } + public static void Multiply(this IReadOnlyCollection units, Length multiplicator, Span 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 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() : null; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Multiply(this Length multiplicator, + IReadOnlyCollection units, Span destination) => units.Multiply(multiplicator, destination); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Multiply(this Length multiplicator, + IReadOnlyCollection units, Span destination) => units.Multiply(multiplicator, destination); + + // === IEnumerable + yeild === + static IEnumerable MultiplyIterator(IEnumerable units, Length multiplicator) + { + foreach (var item in units) + yield return (item.ToDouble() * multiplicator._Value).ToUnit(); + } + static IEnumerable MultiplyNullableIterator(IEnumerable units, Length multiplicator) + { + foreach (PogonMass? item in units) + yield return item.HasValue + ? (item.Value.ToDouble() * multiplicator._Value).ToUnit() : null; + } + + // === IEnumerable === + public static IEnumerable Multiply(this IEnumerable units, Length multiplicator) + { + if (units is null) return null!; + if (units is PogonMass[] array) return array.Multiply(multiplicator); + if (units is List list) return list.Multiply(multiplicator); + if (units is ICollection col) + { + var arr = new Mass[col.Count]; + col.Multiply(multiplicator, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new Mass[roc.Count]; + roc.Multiply(multiplicator, arr); + return arr; + } + return MultiplyIterator(units, multiplicator); + } + public static IEnumerable Multiply(this IEnumerable units, Length multiplicator) + { + if (units is null) return null!; + if (units is PogonMass?[] array) return array.Multiply(multiplicator); + if (units is List list) return list.Multiply(multiplicator); + if (units is ICollection col) + { + var arr = new Mass?[col.Count]; + col.Multiply(multiplicator, arr); + return arr; + } + if (units is IReadOnlyCollection roc) + { + var arr = new Mass?[roc.Count]; + roc.Multiply(multiplicator, arr); + return arr; + } + return MultiplyNullableIterator(units, multiplicator); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IEnumerable Multiply( + this Length multiplicator, IEnumerable units) => Multiply(units, multiplicator); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IEnumerable Multiply( + this Length multiplicator, IEnumerable units) => Multiply(units, multiplicator); + + + + + + + + + + + + + + + + + + internal static void MultiplyCore(this ReadOnlySpan source, Length value, Span destination) { var dVal = value._Value; - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - - var vectorized_Value = new Vector(dVal); - int vectorSize = Vector.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 srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); - var vector = new Vector(srcWindow); - var multiplied = vector * vectorized_Value; - ref double currentDst = ref Unsafe.Add(ref dstRef, i); - Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); - multiplied.CopyTo(dstWindow); - } - - for (; i < len; i++) - { - Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * dVal; - } + source.MultiplyCore(dVal, destination); } internal static void MultiplyCore(this ReadOnlySpan source, PogonMass value, Span destination) { var dVal = value._Value; - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - - var vectorized_Value = new Vector(dVal); - int vectorSize = Vector.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 srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); - var vector = new Vector(srcWindow); - var multiplied = vector * vectorized_Value; - ref double currentDst = ref Unsafe.Add(ref dstRef, i); - Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); - multiplied.CopyTo(dstWindow); - } - - for (; i < len; i++) - { - Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * dVal; - } + source.Multiply(dVal, destination); } diff --git a/QWERTYkez.Mensura/Units/Pogon/PogonXXXXXXXX.Ref.cs b/QWERTYkez.Mensura/Units/Pogon/PogonXXXXXXXX.Ref.cs index 08df7c2..27a6d20 100644 --- a/QWERTYkez.Mensura/Units/Pogon/PogonXXXXXXXX.Ref.cs +++ b/QWERTYkez.Mensura/Units/Pogon/PogonXXXXXXXX.Ref.cs @@ -3,28 +3,54 @@ namespace QWERTYkez.Mensura.Units.Pogon; 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 { 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 { get => new(_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 { get => new(_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 { get => new(_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 { get => new(_Value * LengthConv.KiloMeters.Multiplicator); diff --git a/QWERTYkez.Mensura/Units/Udel/.Udel.cs b/QWERTYkez.Mensura/Units/Udel/.Udel.cs index 8976dd7..2da194b 100644 --- a/QWERTYkez.Mensura/Units/Udel/.Udel.cs +++ b/QWERTYkez.Mensura/Units/Udel/.Udel.cs @@ -1,175 +1,175 @@ -namespace MetricSystem; +//namespace MetricSystem; -/// -/// Base value is PerMilliMeterCubic -/// -[Owned] -public abstract class Udel : Metric> - where U : Udel, new() - where T : Metric, new() -{ - protected override void OnValueChanged() - { - OnPropertyChanged(nameof(PerMeter_PerMilliMeterSquared)); - OnPropertyChanged(nameof(PerMilliMeterCubic)); - OnPropertyChanged(nameof(PerCentiMeterCubic)); - OnPropertyChanged(nameof(PerDeciMeterCubic)); - OnPropertyChanged(nameof(PerMeterCubic)); - OnPropertyChanged(nameof(PerKiloMeterCubic)); - } +///// +///// Base value is PerMilliMeterCubic +///// +//[Owned] +//public abstract class Udel : Metric> +// where U : Udel, new() +// where T : Metric, new() +//{ +// protected override void OnValueChanged() +// { +// OnPropertyChanged(nameof(PerMeter_PerMilliMeterSquared)); +// OnPropertyChanged(nameof(PerMilliMeterCubic)); +// OnPropertyChanged(nameof(PerCentiMeterCubic)); +// OnPropertyChanged(nameof(PerDeciMeterCubic)); +// OnPropertyChanged(nameof(PerMeterCubic)); +// OnPropertyChanged(nameof(PerKiloMeterCubic)); +// } - [NotMapped, JsonIgnore] internal T PerValue - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value, - }; - } - set - { - Value = value.Value; - OnPropertyChanged(nameof(PerValue)); - } - } - [NotMapped, JsonIgnore] public T _PerMilliMeterCubic - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value, - }; - } - set - { - Value = value.Value; - OnPropertyChanged(nameof(_PerMilliMeterCubic)); - } - } +// [NotMapped, JsonIgnore] internal T PerValue +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value, +// }; +// } +// set +// { +// Value = value.Value; +// OnPropertyChanged(nameof(PerValue)); +// } +// } +// [NotMapped, JsonIgnore] public T _PerMilliMeterCubic +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value, +// }; +// } +// set +// { +// Value = value.Value; +// OnPropertyChanged(nameof(_PerMilliMeterCubic)); +// } +// } - [NotMapped, JsonIgnore] public T PerMilliMeterCubic - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value, - }; - } - set - { - Value = value.Value; - OnPropertyChanged(nameof(PerMilliMeterCubic)); - } - } - [NotMapped, JsonIgnore] public T PerMeter_PerMilliMeterSquared - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value * LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2), - BaseContainerMultiplicator = LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2), - }; - } - set - { - Value = value.Value / (LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2)); - OnPropertyChanged(nameof(PerMeter_PerMilliMeterSquared)); - } - } - [NotMapped, JsonIgnore] public T PerCentiMeterCubic - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value * Math.Pow(LengthConv.CentiMeters.Multiplicator, 3), - BaseContainerMultiplicator = Math.Pow(LengthConv.CentiMeters.Multiplicator, 3), - }; - } - set - { - Value = value.Value / Math.Pow(LengthConv.CentiMeters.Multiplicator, 3); - OnPropertyChanged(nameof(PerCentiMeterCubic)); - } - } - [NotMapped, JsonIgnore] public T PerDeciMeterCubic - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value * Math.Pow(LengthConv.DeciMeters.Multiplicator, 3), - BaseContainerMultiplicator = Math.Pow(LengthConv.DeciMeters.Multiplicator, 3), - }; - } - set - { - Value = value.Value / Math.Pow(LengthConv.DeciMeters.Multiplicator, 3); - OnPropertyChanged(nameof(PerDeciMeterCubic)); - } - } - [NotMapped, JsonIgnore] public T PerMeterCubic - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value * Math.Pow(LengthConv.Meters.Multiplicator, 3), - BaseContainerMultiplicator = Math.Pow(LengthConv.Meters.Multiplicator, 3), - }; - } - set - { - Value = value.Value / Math.Pow(LengthConv.Meters.Multiplicator, 3); - OnPropertyChanged(nameof(PerMeterCubic)); - } - } - [NotMapped, JsonIgnore] public T PerKiloMeterCubic - { - get - { - return new() - { - BaseContainer = this, - SilentValueSetter = Value * Math.Pow(LengthConv.KiloMeters.Multiplicator, 3), - BaseContainerMultiplicator = Math.Pow(LengthConv.KiloMeters.Multiplicator, 3), - }; - } - set - { - Value = value.Value / Math.Pow(LengthConv.KiloMeters.Multiplicator, 3); - OnPropertyChanged(nameof(PerKiloMeterCubic)); - } - } +// [NotMapped, JsonIgnore] public T PerMilliMeterCubic +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value, +// }; +// } +// set +// { +// Value = value.Value; +// OnPropertyChanged(nameof(PerMilliMeterCubic)); +// } +// } +// [NotMapped, JsonIgnore] public T PerMeter_PerMilliMeterSquared +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value * LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2), +// BaseContainerMultiplicator = LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2), +// }; +// } +// set +// { +// Value = value.Value / (LengthConv.Meters.Multiplicator * Math.Pow(LengthConv.MilliMeters.Multiplicator, 2)); +// OnPropertyChanged(nameof(PerMeter_PerMilliMeterSquared)); +// } +// } +// [NotMapped, JsonIgnore] public T PerCentiMeterCubic +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value * Math.Pow(LengthConv.CentiMeters.Multiplicator, 3), +// BaseContainerMultiplicator = Math.Pow(LengthConv.CentiMeters.Multiplicator, 3), +// }; +// } +// set +// { +// Value = value.Value / Math.Pow(LengthConv.CentiMeters.Multiplicator, 3); +// OnPropertyChanged(nameof(PerCentiMeterCubic)); +// } +// } +// [NotMapped, JsonIgnore] public T PerDeciMeterCubic +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value * Math.Pow(LengthConv.DeciMeters.Multiplicator, 3), +// BaseContainerMultiplicator = Math.Pow(LengthConv.DeciMeters.Multiplicator, 3), +// }; +// } +// set +// { +// Value = value.Value / Math.Pow(LengthConv.DeciMeters.Multiplicator, 3); +// OnPropertyChanged(nameof(PerDeciMeterCubic)); +// } +// } +// [NotMapped, JsonIgnore] public T PerMeterCubic +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value * Math.Pow(LengthConv.Meters.Multiplicator, 3), +// BaseContainerMultiplicator = Math.Pow(LengthConv.Meters.Multiplicator, 3), +// }; +// } +// set +// { +// Value = value.Value / Math.Pow(LengthConv.Meters.Multiplicator, 3); +// OnPropertyChanged(nameof(PerMeterCubic)); +// } +// } +// [NotMapped, JsonIgnore] public T PerKiloMeterCubic +// { +// get +// { +// return new() +// { +// BaseContainer = this, +// SilentValueSetter = Value * Math.Pow(LengthConv.KiloMeters.Multiplicator, 3), +// BaseContainerMultiplicator = Math.Pow(LengthConv.KiloMeters.Multiplicator, 3), +// }; +// } +// set +// { +// Value = value.Value / Math.Pow(LengthConv.KiloMeters.Multiplicator, 3); +// OnPropertyChanged(nameof(PerKiloMeterCubic)); +// } +// } - public static T operator *(Udel left, Volume right) => ((U)left).Protect()._PerMilliMeterCubic * right.Protect()._MilliMetersCubic; - public static MetricCollection operator *(Udel left, MetricCollection right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); - public static MetricArray operator *(Udel left, MetricArray right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); - public static MetricList operator *(Udel left, MetricList right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); - public static MetricObservableCollection operator *(Udel left, MetricObservableCollection right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); +// public static T operator *(Udel left, Volume right) => ((U)left).Protect()._PerMilliMeterCubic * right.Protect()._MilliMetersCubic; +// public static MetricCollection operator *(Udel left, MetricCollection right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); +// public static MetricArray operator *(Udel left, MetricArray right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); +// public static MetricList operator *(Udel left, MetricList right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); +// public static MetricObservableCollection operator *(Udel left, MetricObservableCollection right) => right.MetricSelect(r => ((U)left).Protect() * r.Protect()); - public static T operator *(Volume left, Udel right) => ((U)right).Protect()._PerMilliMeterCubic * left.Protect()._MilliMetersCubic; - public static MetricCollection operator *(MetricCollection left, Udel right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); - public static MetricArray operator *(MetricArray left, Udel right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); - public static MetricList operator *(MetricList left, Udel right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); - public static MetricObservableCollection operator *(MetricObservableCollection left, Udel right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); +// public static T operator *(Volume left, Udel right) => ((U)right).Protect()._PerMilliMeterCubic * left.Protect()._MilliMetersCubic; +// public static MetricCollection operator *(MetricCollection left, Udel right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); +// public static MetricArray operator *(MetricArray left, Udel right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); +// public static MetricList operator *(MetricList left, Udel right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); +// public static MetricObservableCollection operator *(MetricObservableCollection left, Udel right) => left.MetricSelect(r => ((U)right).Protect() * r.Protect()); - public static Volume operator /(T left, Udel right) => new() { _MilliMetersCubic = left.Protect() / ((U)right).Protect()._PerMilliMeterCubic }; - public static MetricCollection operator *(MetricCollection left, Udel right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); - public static MetricArray operator *(MetricArray left, Udel right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); - public static MetricList operator *(MetricList left, Udel right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); - public static MetricObservableCollection operator *(MetricObservableCollection left, Udel right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); -} \ No newline at end of file +// public static Volume operator /(T left, Udel right) => new() { _MilliMetersCubic = left.Protect() / ((U)right).Protect()._PerMilliMeterCubic }; +// public static MetricCollection operator *(MetricCollection left, Udel right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); +// public static MetricArray operator *(MetricArray left, Udel right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); +// public static MetricList operator *(MetricList left, Udel right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); +// public static MetricObservableCollection operator *(MetricObservableCollection left, Udel right) => left.MetricSelect(l => l.Protect() / ((U)right).Protect()); +//} \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/Udel/UdelForce.cs b/QWERTYkez.Mensura/Units/Udel/UdelForce.cs index 8000a66..4e9c314 100644 --- a/QWERTYkez.Mensura/Units/Udel/UdelForce.cs +++ b/QWERTYkez.Mensura/Units/Udel/UdelForce.cs @@ -1,16 +1,16 @@ -namespace MetricSystem; +//namespace MetricSystem; -[Owned, JsonConverter(typeof(MetricFormatter)), DebuggerDisplay("N/(m*mm2) = {PerMeter_PerMilliMeterSquared._Newtons.ToString(\"0.###\")}, kgf/(m*mm2) = {PerMeter_PerMilliMeterSquared.KiloGramForces.ToString(\"0.###\")}")] -public partial class UdelForce : Udel -{ - [CollectionsOperatorsGenerator] public static PogonForce operator *(Area left, UdelForce right) => right * left; +//[Owned, JsonConverter(typeof(MetricFormatter)), DebuggerDisplay("N/(m*mm2) = {PerMeter_PerMilliMeterSquared._Newtons.ToString(\"0.###\")}, kgf/(m*mm2) = {PerMeter_PerMilliMeterSquared.KiloGramForces.ToString(\"0.###\")}")] +//public partial class UdelForce : Udel +//{ +// [CollectionsOperatorsGenerator] public static PogonForce operator *(Area left, UdelForce right) => right * left; - [CollectionsOperatorsGenerator] public static PogonForce operator *(UdelForce left, Area right) => left.MultiplyProtected(right, PogonForceCoeff); - static readonly double PogonForceCoeff = Coefficients.MultiplyCoefficient(a => a._PerMilliMeterCubic.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeter.Value = 1); -} +// [CollectionsOperatorsGenerator] public static PogonForce operator *(UdelForce left, Area right) => left.MultiplyProtected(right, PogonForceCoeff); +// static readonly double PogonForceCoeff = Coefficients.MultiplyCoefficient(a => a._PerMilliMeterCubic.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeter.Value = 1); +//} -public partial class Volume : Metric -{ - [CollectionsOperatorsGenerator] public static UdelForce operator /(Force left, Volume right) => left.DivideProtected(right, UdelForceCoeff); - static readonly double UdelForceCoeff = Coefficients.DivideCoefficient(a => a.Value = 1, b => b._MilliMetersCubic = 1, r => r._PerMilliMeterCubic.Value = 1); -} \ No newline at end of file +//public partial class Volume : Metric +//{ +// [CollectionsOperatorsGenerator] public static UdelForce operator /(Force left, Volume right) => left.DivideProtected(right, UdelForceCoeff); +// static readonly double UdelForceCoeff = Coefficients.DivideCoefficient(a => a.Value = 1, b => b._MilliMetersCubic = 1, r => r._PerMilliMeterCubic.Value = 1); +//} \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/Udel/UdelMass (Density).cs b/QWERTYkez.Mensura/Units/Udel/UdelMass (Density).cs index 7268860..30d4bd7 100644 --- a/QWERTYkez.Mensura/Units/Udel/UdelMass (Density).cs +++ b/QWERTYkez.Mensura/Units/Udel/UdelMass (Density).cs @@ -1,16 +1,16 @@ -namespace MetricSystem; +//namespace MetricSystem; -[Owned, JsonConverter(typeof(MetricFormatter)), DebuggerDisplay("gr/(m*mm2) = {PerMeter_PerMilliMeterSquared._Grams.ToString(\"0.###\")}, kg/(m*mm2) = {PerMeter_PerMilliMeterSquared.KiloGrams.ToString(\"0.###\")}")] -public partial class Density : Udel -{ - [CollectionsOperatorsGenerator] public static PogonMass operator *(Area left, Density right) => right * left; +//[Owned, JsonConverter(typeof(MetricFormatter)), DebuggerDisplay("gr/(m*mm2) = {PerMeter_PerMilliMeterSquared._Grams.ToString(\"0.###\")}, kg/(m*mm2) = {PerMeter_PerMilliMeterSquared.KiloGrams.ToString(\"0.###\")}")] +//public partial class Density : Udel +//{ +// [CollectionsOperatorsGenerator] public static PogonMass operator *(Area left, Density right) => right * left; - [CollectionsOperatorsGenerator] public static PogonMass operator *(Density left, Area right) => left.MultiplyProtected(right, PogonMassCoeff); - static readonly double PogonMassCoeff = Coefficients.MultiplyCoefficient(a => a._PerMilliMeterCubic.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeter.Value = 1); -} +// [CollectionsOperatorsGenerator] public static PogonMass operator *(Density left, Area right) => left.MultiplyProtected(right, PogonMassCoeff); +// static readonly double PogonMassCoeff = Coefficients.MultiplyCoefficient(a => a._PerMilliMeterCubic.Value = 1, b => b._MilliMetersSquared = 1, r => r._PerMilliMeter.Value = 1); +//} -public partial class Volume : Metric -{ - [CollectionsOperatorsGenerator] public static Density operator /(Mass left, Volume right) => left.DivideProtected(right, DensityCoeff); - static readonly double DensityCoeff = Coefficients.DivideCoefficient(a => a.Value = 1, b => b._MilliMetersCubic = 1, r => r._PerMilliMeterCubic.Value = 1); -} \ No newline at end of file +//public partial class Volume : Metric +//{ +// [CollectionsOperatorsGenerator] public static Density operator /(Mass left, Volume right) => left.DivideProtected(right, DensityCoeff); +// static readonly double DensityCoeff = Coefficients.DivideCoefficient(a => a.Value = 1, b => b._MilliMetersCubic = 1, r => r._PerMilliMeterCubic.Value = 1); +//} \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs b/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs index 187e1d0..b19fac3 100644 --- a/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs +++ b/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs @@ -1,5 +1,7 @@ #if DEBUG +global using XXXXXXXXXXXXXXExtensions = QWERTYkez.Mensura.Units.XXXXXXXXXXXXXXExtensions; global using XXXXXXXXXXXXXX = QWERTYkez.Mensura.Units.XXXXXXXXXXXXXX; + using System.Runtime.Serialization; namespace QWERTYkez.Mensura.Units; @@ -39,14 +41,13 @@ public readonly partial record struct XXXXXXXXXXXXXX : IMensuraUnit 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 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 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.Protected() < T2.Protected(); + 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.Protected() >= T2.Protected(); public static XXXXXXXXXXXXXX operator +(XXXXXXXXXXXXXX T2) => new(+T2._Value); @@ -191,4 +192,9 @@ public readonly partial record struct XXXXXXXXXXXXXX : IMensuraUnit() where R : struct, IMensuraUnit, IEquatable => Math.Sqrt(_Value).ToUnit(); } + +public static class XXXXXXXXXXXXXXExtensions +{ + public static double Protected(this XXXXXXXXXXXXXX? unit) => unit is null ? 0d : unit.Value._Value; +} #endif \ No newline at end of file